Definitelytyped: [styled-components] Optional types passed down as required

Created on 18 Oct 2018  路  13Comments  路  Source: DefinitelyTyped/DefinitelyTyped

I opened this issue and was oriented to reopen it here.

I'm trying to customize some Material UI components using Styled Components, however, once I wrap the MUI component with styled hoc TypeScript starts to warn regarding some props are not provided. Looking at MUI props definitions all of them are optional. If I use the pure MUI component it works fine.

Code example:

```
import styled from 'styled-components';
import { TextField } from '@material-ui/core';

const TextFieldStyled = styled(TextField)``
/* This returns missing props warning */
name={name}
label={label}
value={value}
onChange={onChange}
/>

/* This works fine */
name={name}
label={label}
value={value}
onChange={onChange}
/>
```

I found this PR that was used to solve a passing down props issue https://github.com/styled-components/styled-components/pull/1427/files

After updating the code to pass the props as partial. I tested and the warning is gone.
https://github.com/soutot/styled-components/blob/master/typings/styled-components.d.ts#L56

I'd like to share this with you and check if this is the correct approach or if this error was not suppose to happen and I'm missing something.

My package.json contains
"styled-components": "^3.4.9"
"@material-ui/core": "^3.2.0",
"@types/material-ui": "^0.21.5",

Thanks

@Igorbek @Igmat @Lavoaster

Most helpful comment

Why would it be an issue with MUI's type when

const SubmitButton = styled(Button)`
  float: right;
  margin-right: 20px;
` as typeof Button;

works perfectly?

All 13 comments

It seems like something in the declaration file for SC is using a non-homomophic mapped type (see https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html).

@nickmccurdy I'm not sure if I got what you mean. Where is this file that you mentioned? I coudln't find any ternary condition that may fit the docs description you provided
https://github.com/soutot/styled-components/blob/master/typings/styled-components.d.ts

My project is experiencing the same issue as what's reported here. Previously we were on 2.4 of SC and uncovered this during update. The error seems similar to what's reported in https://github.com/DefinitelyTyped/DefinitelyTyped/issues/30942 but I don't know enough about SC or MUI to say for sure. (Upon closer inspection, I don't think this is related after all.)

For completeness, with

"@types/styled-components": "^4.1.3",
"@material-ui/core": "^3.6.1",
"@types/react": "^16.7.9",
"typescript": "3.2.1",

and something like

import styled from 'styled-components';
import Button from '@material-ui/core/Button';

const SubmitButton = styled(Button)`
  float: right;
  margin-right: 20px;
`;

I'll get a warning like the following when in use:

Type '{ children: string; disabled: false; onClick: () => void; variant: "contained"; }' is missing the following properties from type 'Pick<Pick<ButtonProps | (ButtonProps & RefAttributes<Component<ButtonProps, any, any>>), "disabled" | "media" | "hidden" | "dir" | "form" | "slot" | "style" | "title" | ... 274 more ... | "disableFocusRipple"> & Partial<...>, "disabled" | ... 281 more ... | "disableFocusRipple">': style, size, className, innerRef, classes

It seems changing the definition of Button to use React.ComponentClass instead of React.ComponentType fixes it. This is likely an issue with @material-ui's types, but still strange that it broke as this was not supposed to be a breaking change.

Why would it be an issue with MUI's type when

const SubmitButton = styled(Button)`
  float: right;
  margin-right: 20px;
` as typeof Button;

works perfectly?

@Kovensy, could you clarify your reported fix? Which type specification are you changing?

@material-ui's types are specifying that Button is simultaneously "either a ComponentClass or FunctionComponent", but neither of those are assignable to something that is only a ComponentClass or only a FunctionComponent.

import Button from '@material-ui/core/Button'

declare function test(component: ComponentClass<any>): void
declare function test(component: FunctionComponent<any>): void

test(Button) // type error, Button not assignable to either overload

Button is declared as a function component so it needs to be exported as a function component.


The reason why this is a problem now is that styled now cares about the _type_ of the component, not only what props it receives. This is important for correctly supporting refs (the previous version just anyed refs).

The way it works right now is indeed not ideal, I/we need to come up with new primitives for declaring higher order components that can correctly infer refs and preserve .defaultProps. https://github.com/DefinitelyTyped/DefinitelyTyped/pull/30913

@Jessidhia Do you possibly have news for the material-ui issue? The workaround exists, but it's definitely ugly and makes things complicated.

@Jessidhia If we have a union of two types and one accepts a prop and one not then one should assume that the union does not accept the prop before the union was narrowed. That's at least how typescript does it.

I don't understand why styled-components is essentially bailing out instead of assuming that the union of FunctionComponent | ClassComponent does not accept a ref prop.

Edit:
Not only that but styled-components should only look at the props of a ReactType. Is it not possible to infer the props of a given ReactType and then check if ref is present there?

Edit2:
Actual explanation what caused this issue: Pick looses all type informations regarding the union type: Pick<ButtonProps | (ButtonProps & { children?: ReactNode })> will return a type where every property is required. ref inferrence is working fine.

I also get "props not provided" errors with Ant design components

This workaround is working for me currently:

const StyledButton = styled((props: ButtonProps) => (
  <Button {...props} />
))``

@jaycle THANK YOU.

This is not specific to MUI. I also get this error when using components generated by styled-svg

getting the same issue when using antd button.

packages are:
"antd": "^3.10.8",
"@types/antd": "^1.0.0",
"@types/react": "^16.4.4",
"react": "^16.8.3",
"typescript": "3.3.3333",

@jaycle fix works.
https://github.com/DefinitelyTyped/DefinitelyTyped/issues/29832#issuecomment-443694781

styled(Button)`
        width: 56px;
        height: 56px;
    ` as unknown as typeof Button
Was this page helpful?
0 / 5 - 0 ratings

Related issues

jgoz picture jgoz  路  3Comments

JWT
svipas picture svipas  路  3Comments

Loghorn picture Loghorn  路  3Comments

tyv picture tyv  路  3Comments

victor-guoyu picture victor-guoyu  路  3Comments