From ecc3fd0ff3ec91da0c14d798a69f877a5c297325 Mon Sep 17 00:00:00 2001 From: Matt Tingen Date: Tue, 12 Mar 2019 22:27:11 -0400 Subject: [PATCH] Fix optionality of inferred props --- types/react/index.d.ts | 16 +++++++++------- types/react/test/managedAttributes.tsx | 23 +++++++++++++++++++++++ 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/types/react/index.d.ts b/types/react/index.d.ts index d7fcb51d61..554d05fc70 100644 --- a/types/react/index.d.ts +++ b/types/react/index.d.ts @@ -2732,16 +2732,18 @@ declare namespace React { // so boolean is only resolved for T = any type IsExactlyAny = boolean extends (T extends never ? true : false) ? true : false; +// Pick properties for which the value is `any` +type PickAny = Pick extends true ? K : never }[keyof T]>; + // Try to resolve ill-defined props like for JS users: props can be any, or sometimes objects with properties of type any // If props is type any, use propTypes definitions, otherwise for each `any` property of props, use the propTypes type // If declared props have indexed properties, ignore inferred props entirely as keyof gets widened -type MergePropTypes = IsExactlyAny

extends true ? T : ({ - [K in keyof P]: IsExactlyAny extends true - ? K extends keyof T - ? T[K] - : P[K] - : P[K] -} & Pick>); +type MergePropTypes = IsExactlyAny

extends true ? T : string extends keyof P ? P : ( + // From declared props, pick properties which are either not `any` or are missing on `propTypes`. + & Pick> | Exclude> + // From inferred props, pick all properties except those which are not `any` on `Props` + & Pick>>> +); // Any prop that has a default prop becomes optional, but its type is unchanged // Undeclared default props are augmented into the resulting allowable attributes diff --git a/types/react/test/managedAttributes.tsx b/types/react/test/managedAttributes.tsx index 9939cffb15..d60e75e5a0 100644 --- a/types/react/test/managedAttributes.tsx +++ b/types/react/test/managedAttributes.tsx @@ -235,17 +235,40 @@ interface LeaveMeAloneDtslint { foo: string; } // foo: string; // bar: any; // } +// interface WeakComponentProps3 { +// foo: any; +// bar: any; +// } // // $ExpectType true // type weakComponentTest1 = JSX.LibraryManagedAttributes<{ propTypes: typeof weakComponentPropTypes }, any> extends { // foo?: string | null // bar: boolean // } ? true : false; +// // $ExpectType true // type weakComponentTest2 = JSX.LibraryManagedAttributes<{ propTypes: typeof weakComponentPropTypes }, WeakComponentProps1> extends { // foo?: string | null // bar: number // } ? true : false; +// // $ExpectType true // type weakComponentTest3 = JSX.LibraryManagedAttributes<{ propTypes: typeof weakComponentPropTypes }, WeakComponentProps2> extends { // foo: string // bar: boolean // } ? true : false; + +// // $ExpectError +// const weakComponentOptionalityTest1: JSX.LibraryManagedAttributes<{ propTypes: typeof weakComponentPropTypes }, WeakComponentProps3> = { foo: '' }; +// const weakComponentOptionalityTest2: JSX.LibraryManagedAttributes<{ propTypes: typeof weakComponentPropTypes }, WeakComponentProps3> = { bar: true }; + +// interface IndexedComponentProps { +// [K: string]: boolean; +// } +// interface WeakIndexedComponentProps { +// [K: string]: any; +// } + +// const weakComponentIndexedTest1: JSX.LibraryManagedAttributes<{ propTypes: typeof weakComponentPropTypes }, IndexedComponentProps> = { }; +// // $ExpectError +// const weakComponentIndexedTest2: JSX.LibraryManagedAttributes<{ propTypes: typeof weakComponentPropTypes }, IndexedComponentProps> = { foo: '' }; +// const weakComponentIndexedTest3: JSX.LibraryManagedAttributes<{ propTypes: typeof weakComponentPropTypes }, WeakIndexedComponentProps> = { foo: '' }; +// const weakComponentIndexedTest4: JSX.LibraryManagedAttributes<{ propTypes: typeof weakComponentPropTypes }, WeakIndexedComponentProps> = { foo: 4 };