Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[core] In typescript-to-proptypes, respect the value pass to the generic #34311

Merged
merged 1 commit into from Sep 16, 2022

Conversation

flaviendelangle
Copy link
Member

@flaviendelangle flaviendelangle commented Sep 14, 2022

While working on X, I noticed that the generation of the proptypes does not work well in the following scenario:

type Type = 'one' | 'two' | 'three'

interface ParentProps<T extends Type> {
  A: T;
}

interface ChildProps extends ParentProps<'one' | 'two'> {}

export function Foo(props: ChildProps): JSX.Element;

// Should output:
Foo.propTypes = {
  A: PropTypes.oneOf(['one', 'two']).isRequired,
};

// But outputs:
Foo.propTypes = {
  A: PropTypes.oneOf(['one', 'two', 'three']).isRequired,
};

We even looses the optional in the following scenario:

type Type = 'one' | 'two' | 'three'

interface ParentProps<T extends Type> {
  A: T;
}

interface ChildProps extends Partial<ParentProps<'one' | 'two'>> {}

export function Foo(props: ChildProps): JSX.Element;

// Should output:
Foo.propTypes = {
  A: PropTypes.oneOf(['one', 'two']),
};

// But outputs:
Foo.propTypes = {
  A: PropTypes.oneOf(['one', 'two', 'three']).isRequired,
};

The issue is that, when we have a prop that equals a generic value, then we apply its base constraints (in <A extends B>, we apply B).
From what I understand, it was purely done to avoid weird behaviors for scenario like <A extends React.ElementType>, where TTP was considering A as a union.


My solution is simply to only keep this custom behavior for React.ElementType.
It is not 100% safe, if you have a better idea I am open of course.

There was one issue on the AutoComplete component with the generics that have undefined by default.
Before, ttp generated the type from there constrain (boolean | undefined), but now it generates the type from the whole type. And the behavior in that situation was to apply the default value.
But you can't create a proptype for something always undefined.
I think it's better to apply the constraint in this scenario rather than the default value.

export interface AutocompleteProps<
  DisableClearable extends boolean | undefined = undefined,
> {
  disableClearable?: DisableClearable;
}

@flaviendelangle flaviendelangle self-assigned this Sep 14, 2022
@flaviendelangle flaviendelangle added the core Infrastructure work going on behind the scenes label Sep 14, 2022
@mui-bot
Copy link

mui-bot commented Sep 14, 2022

No bundle size changes

Generated by 🚫 dangerJS against 3892496

@@ -186,12 +186,6 @@ export function parseFromProgram(
return t.createObjectType({ jsDoc: undefined });
}

const defaultGenericType = type.getDefault();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will no longer use the default value but the actual value passed to the generic or the constraint if no value is passed.

@flaviendelangle flaviendelangle changed the title [core] In typescript-to-proptypes, respect the value pass to the generic [core] In typescript-to-proptypes, respect the value pass to the generic Sep 14, 2022
propTypes?: any;
}

export interface MultiSelectUnstyledOwnerState<TValue extends {}>
extends MultiSelectUnstyledProps<TValue> {
export interface MultiSelectUnstyledOwnerState<TValue> extends MultiSelectUnstyledProps<TValue> {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For all those changes, I don't understand the typing. We have TValue extends {}, but in the example we often pass strings.

Is this constrain wrong ?
Should we put another constraint ?
Is the inconsistency intended ?

With the prop types correctly generated, I had test failing.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

string does extend {}. T extends {} basically means you can't provide null or undefined to the generic parameter.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a better solution would be to detect the extends {} constraint and generate the PropTypes.any constraint from it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done 👍

@flaviendelangle
Copy link
Member Author

flaviendelangle commented Sep 15, 2022

Current diff on mui-x with this PR.
For me everything make sense.

diff --git a/packages/grid/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx b/packages/grid/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx
index 2e6b955f0..647db9951 100644
--- a/packages/grid/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx
+++ b/packages/grid/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx
@@ -833,8 +833,8 @@ DataGridPremiumRaw.propTypes = {
    * Rows data to pin on top or bottom.
    */
   pinnedRows: PropTypes.shape({
-    bottom: PropTypes.array,
-    top: PropTypes.array,
+    bottom: PropTypes.arrayOf(PropTypes.object),
+    top: PropTypes.arrayOf(PropTypes.object),
   }),
   /**
    * Callback called before updating a row with new values in the row and cell editing.
@@ -882,7 +882,7 @@ DataGridPremiumRaw.propTypes = {
   /**
    * Set of rows of type [[GridRowsProp]].
    */
-  rows: PropTypes.array.isRequired,
+  rows: PropTypes.arrayOf(PropTypes.object).isRequired,
   /**
    * Loading rows can be processed on the server or client-side.
    * Set it to 'client' if you would like enable infnite loading.
diff --git a/packages/grid/x-data-grid-premium/src/components/GridExcelExportMenuItem.tsx b/packages/grid/x-data-grid-premium/src/components/GridExcelExportMenuItem.tsx
index 79e6e187b..d7d83d437 100644
--- a/packages/grid/x-data-grid-premium/src/components/GridExcelExportMenuItem.tsx
+++ b/packages/grid/x-data-grid-premium/src/components/GridExcelExportMenuItem.tsx
@@ -31,7 +31,17 @@ GridExcelExportMenuItem.propTypes = {
   // ----------------------------------------------------------------------
   hideMenu: PropTypes.func,
   options: PropTypes.shape({
+    allColumns: PropTypes.bool,
+    columnsStyles: PropTypes.object,
     disableToolbarButton: PropTypes.bool,
+    exceljsPostProcess: PropTypes.func,
+    exceljsPreProcess: PropTypes.func,
+    fields: PropTypes.arrayOf(PropTypes.string),
+    fileName: PropTypes.string,
+    getRowsToExport: PropTypes.func,
+    includeColumnGroupsHeaders: PropTypes.bool,
+    includeHeaders: PropTypes.bool,
+    valueOptionsSheetName: PropTypes.string,
   }),
 } as any;
 
diff --git a/packages/grid/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx b/packages/grid/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx
index 5af063bfe..7fb91609a 100644
--- a/packages/grid/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx
+++ b/packages/grid/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx
@@ -784,8 +784,8 @@ DataGridProRaw.propTypes = {
    * Rows data to pin on top or bottom.
    */
   pinnedRows: PropTypes.shape({
-    bottom: PropTypes.array,
-    top: PropTypes.array,
+    bottom: PropTypes.arrayOf(PropTypes.object),
-    top: PropTypes.array,
+    bottom: PropTypes.arrayOf(PropTypes.object),
+    top: PropTypes.arrayOf(PropTypes.object),
   }),
   /**
    * Callback called before updating a row with new values in the row and cell editing.
@@ -823,7 +823,7 @@ DataGridProRaw.propTypes = {
   /**
    * Set of rows of type [[GridRowsProp]].
    */
-  rows: PropTypes.array.isRequired,
+  rows: PropTypes.arrayOf(PropTypes.object).isRequired,
   /**
    * Loading rows can be processed on the server or client-side.
    * Set it to 'client' if you would like enable infnite loading.
diff --git a/packages/grid/x-data-grid-pro/src/components/GridDetailPanelToggleCell.tsx b/packages/grid/x-data-grid-pro/src/components/GridDetailPanelToggleCell.tsx
index 2b388d6dd..c7536e6c8 100644
--- a/packages/grid/x-data-grid-pro/src/components/GridDetailPanelToggleCell.tsx
+++ b/packages/grid/x-data-grid-pro/src/components/GridDetailPanelToggleCell.tsx
@@ -115,7 +115,7 @@ GridDetailPanelToggleCell.propTypes = {
   /**
    * The row model of the row that the current cell belongs to.
    */
-  row: PropTypes.object.isRequired,
+  row: PropTypes.any.isRequired,
   /**
    * The node of the row that the current cell belongs to.
    */
diff --git a/packages/grid/x-data-grid-pro/src/components/GridTreeDataGroupingCell.tsx b/packages/grid/x-data-grid-pro/src/components/GridTreeDataGroupingCell.tsx
index 733153536..721694bbd 100644
--- a/packages/grid/x-data-grid-pro/src/components/GridTreeDataGroupingCell.tsx
+++ b/packages/grid/x-data-grid-pro/src/components/GridTreeDataGroupingCell.tsx
@@ -154,7 +154,7 @@ GridTreeDataGroupingCell.propTypes = {
   /**
    * The row model of the row that the current cell belongs to.
    */
-  row: PropTypes.object.isRequired,
+  row: PropTypes.any.isRequired,
   /**
    * The node of the row that the current cell belongs to.
    */
diff --git a/packages/grid/x-data-grid/src/DataGrid/DataGrid.tsx b/packages/grid/x-data-grid/src/DataGrid/DataGrid.tsx
index 7058730b1..b6df72756 100644
--- a/packages/grid/x-data-grid/src/DataGrid/DataGrid.tsx
+++ b/packages/grid/x-data-grid/src/DataGrid/DataGrid.tsx
@@ -663,7 +663,7 @@ DataGridRaw.propTypes = {
   /**
    * Set of rows of type [[GridRowsProp]].
    */
-  rows: PropTypes.array.isRequired,
+  rows: PropTypes.arrayOf(PropTypes.object).isRequired,
   /**
    * Sets the type of space between rows added by `getRowSpacing`.
    * @default "margin"
diff --git a/packages/grid/x-data-grid/src/components/cell/GridActionsCell.tsx b/packages/grid/x-data-grid/src/components/cell/GridActionsCell.tsx
index def9355e9..879440ff6 100644
--- a/packages/grid/x-data-grid/src/components/cell/GridActionsCell.tsx
+++ b/packages/grid/x-data-grid/src/components/cell/GridActionsCell.tsx
@@ -302,7 +302,7 @@ GridActionsCell.propTypes = {
   /**
    * The row model of the row that the current cell belongs to.
    */
-  row: PropTypes.object.isRequired,
+  row: PropTypes.any.isRequired,
   /**
    * The node of the row that the current cell belongs to.
    */
diff --git a/packages/grid/x-data-grid/src/components/cell/GridBooleanCell.tsx b/packages/grid/x-data-grid/src/components/cell/GridBooleanCell.tsx
index a8af71a5e..ddd528b76 100644
--- a/packages/grid/x-data-grid/src/components/cell/GridBooleanCell.tsx
+++ b/packages/grid/x-data-grid/src/components/cell/GridBooleanCell.tsx
@@ -129,7 +129,7 @@ GridBooleanCellRaw.propTypes = {
   /**
    * The row model of the row that the current cell belongs to.
    */
-  row: PropTypes.object.isRequired,
+  row: PropTypes.any.isRequired,
   /**
    * The node of the row that the current cell belongs to.
    */
diff --git a/packages/grid/x-data-grid/src/components/cell/GridEditBooleanCell.tsx b/packages/grid/x-data-grid/src/components/cell/GridEditBooleanCell.tsx
index 3cbcd3f1f..352dc3aee 100644
--- a/packages/grid/x-data-grid/src/components/cell/GridEditBooleanCell.tsx
+++ b/packages/grid/x-data-grid/src/components/cell/GridEditBooleanCell.tsx
@@ -170,7 +170,7 @@ GridEditBooleanCell.propTypes = {
   /**
    * The row model of the row that the current cell belongs to.
    */
-  row: PropTypes.object.isRequired,
+  row: PropTypes.any.isRequired,
   /**
    * The node of the row that the current cell belongs to.
    */
diff --git a/packages/grid/x-data-grid/src/components/cell/GridEditDateCell.tsx b/packages/grid/x-data-grid/src/components/cell/GridEditDateCell.tsx
index 532798fde..59f7ba32c 100644
--- a/packages/grid/x-data-grid/src/components/cell/GridEditDateCell.tsx
+++ b/packages/grid/x-data-grid/src/components/cell/GridEditDateCell.tsx
@@ -220,7 +220,7 @@ GridEditDateCell.propTypes = {
   /**
    * The row model of the row that the current cell belongs to.
    */
-  row: PropTypes.object.isRequired,
+  row: PropTypes.any.isRequired,
   /**
    * The node of the row that the current cell belongs to.
    */
diff --git a/packages/grid/x-data-grid/src/components/cell/GridEditInputCell.tsx b/packages/grid/x-data-grid/src/components/cell/GridEditInputCell.tsx
index c5f77ed1b..8200eba4c 100644
--- a/packages/grid/x-data-grid/src/components/cell/GridEditInputCell.tsx
+++ b/packages/grid/x-data-grid/src/components/cell/GridEditInputCell.tsx
@@ -200,7 +200,7 @@ GridEditInputCell.propTypes = {
   /**
    * The row model of the row that the current cell belongs to.
    */
-  row: PropTypes.object,
+  row: PropTypes.any,
   /**
    * The node of the row that the current cell belongs to.
    */
diff --git a/packages/grid/x-data-grid/src/components/cell/GridEditSingleSelectCell.tsx b/packages/grid/x-data-grid/src/components/cell/GridEditSingleSelectCell.tsx
index abeea1b5d..59f168615 100644
--- a/packages/grid/x-data-grid/src/components/cell/GridEditSingleSelectCell.tsx
+++ b/packages/grid/x-data-grid/src/components/cell/GridEditSingleSelectCell.tsx
@@ -256,7 +256,7 @@ GridEditSingleSelectCell.propTypes = {
   /**
    * The row model of the row that the current cell belongs to.
    */
-  row: PropTypes.object.isRequired,
+  row: PropTypes.any.isRequired,
   /**
    * The node of the row that the current cell belongs to.
    */
diff --git a/packages/grid/x-data-grid/src/components/columnSelection/GridCellCheckboxRenderer.tsx b/packages/grid/x-data-grid/src/components/columnSelection/GridCellCheckboxRenderer.tsx
index 9acac0b7d..a659ff93b 100644
--- a/packages/grid/x-data-grid/src/components/columnSelection/GridCellCheckboxRenderer.tsx
+++ b/packages/grid/x-data-grid/src/components/columnSelection/GridCellCheckboxRenderer.tsx
@@ -181,7 +181,7 @@ GridCellCheckboxForwardRef.propTypes = {
   /**
    * The row model of the row that the current cell belongs to.
    */
-  row: PropTypes.object.isRequired,
+  row: PropTypes.any.isRequired,
   /**
    * The node of the row that the current cell belongs to.
    */

Copy link
Member

@siriwatknp siriwatknp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 I don't see any downsides.

Copy link
Member

@michaldudak michaldudak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great now! Thanks!

Copy link

@ProKashif ProKashif left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@oliviertassinari
Copy link
Member

oliviertassinari commented Sep 17, 2022

@ProKashif Sorry, I have blocked you from the MUI organization, per this review activity:

Screenshot 2022-09-17 at 13 16 09

https://github.com/ProKashif?tab=overview&from=2022-08-01&to=2022-08-31

daniel-rabe pushed a commit to daniel-rabe/material-ui that referenced this pull request Nov 29, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core Infrastructure work going on behind the scenes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants