diff --git a/types/styled-components/index.d.ts b/types/styled-components/index.d.ts index b940965ace..1ab41d31e1 100644 --- a/types/styled-components/index.d.ts +++ b/types/styled-components/index.d.ts @@ -32,6 +32,21 @@ export interface ThemeProps { export type ThemedStyledProps = P & ThemeProps; export type StyledProps

= ThemedStyledProps>; +// Any prop that has a default prop becomes optional, but its type is unchanged +// Undeclared default props are augmented into the resulting allowable attributes +// If declared props have indexed properties, ignore default props entirely as keyof gets widened +// Wrap in an outer-level conditional type to allow distribution over props that are unions +type Defaultize = P extends any + ? string extends keyof P ? P : + & Pick> + & Partial>> + & Partial>> + : never; + +type ReactDefaultizedProps = C extends { defaultProps: infer D; } + ? Defaultize + : P; + export type StyledComponentProps< // The Component from whose props are derived C extends keyof JSX.IntrinsicElements | React.ComponentType, @@ -42,8 +57,13 @@ export type StyledComponentProps< // The props that are made optional by .attrs A extends keyof any > = WithOptionalTheme< - Omit & O, A> & - Partial & O, A>>, + Omit< + ReactDefaultizedProps< + C, + React.ComponentPropsWithRef + > & O, + A + > & Partial & O, A>>, T >; @@ -156,8 +176,6 @@ export interface StyledComponentBase< } ): React.ReactElement>; - readonly defaultProps: ReactDefaultProps; - withComponent( component: WithC ): StyledComponent< diff --git a/types/styled-components/test/index.tsx b/types/styled-components/test/index.tsx index 96867cf288..7108f737f7 100644 --- a/types/styled-components/test/index.tsx +++ b/types/styled-components/test/index.tsx @@ -978,9 +978,25 @@ function validateDefaultProps() { ; - // this test is failing in TS 3.0 but not in 3.1 - // ; + ; // still respects the type of optionalProp ; // $ExpectError + + // example of a simple helper that sets defaultProps and update the type + type WithDefaultProps = C & { defaultProps: D }; + function withDefaultProps(component: C, defaultProps: D): WithDefaultProps { + (component as WithDefaultProps).defaultProps = defaultProps; + return component as WithDefaultProps; + } + + const OtherStyledComponent = withDefaultProps( + styled(MyComponent)` color: red `, + { requiredProp: true } + ); + + // this test is failing in TS 3.1 but not in 3.2 + // ; + + ; // $ExpectError }