reactjs - Styled Components, nødvendige props definert som defaultProps vises som manglende
Påkrevde egenskaper som er definert som defaultProps vises som manglende når du bruker komponenten.
// Button.ts
interface ButtonProps {
size: 'small' | 'medium' | 'large';
inverted: boolean;
raised: boolean;
}
const Button = styled('button')<ButtonProps>`...`
Button.defaultProps = {
size: 'medium',
inverted: false,
raised: false,
}
export default Button
// Hello.tsx
import Button from './Button'
const Hello = () => <Button>Hello</Button>
Knappen er uthevet i rødt og viser denne feilmeldingen:
Type '{}' is missing the following properties from type
'Pick<Pick<Pick<DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>,
HTMLButtonElement>, "form" | "style" | "title" | "key" | "autoFocus" |
"disabled" | "formAction" | ... 255 more ... | "onTransitionEndCapture"> &
{ ...; } & ButtonProps, "form" | ... 329 more ... | "raised"> &
Partial<...>, "form" | ... 329 ...': size, inverted, and 1 more.
Versjoner :
"@types/styled-components": "^4.1.9",
"@types/react": "^16.8.5",
"@types/react-dom": "^16.8.2",
"typescript": "^3.3.3333",
"styled-components": "^4.1.3"
"react": "^16.8.3",
"react-dom": "^16.8.3",
Svar #1
Rediger Selv om jeg personlig er ok med denne oppførselen, er den ikke i samsvar med oppførselen til en vanlig React-komponent (TypeScript støtter defaultProps).
Jeg ser meg litt rundt, og det ser ut til at dette ble fikset i @types/styled-components, men deretter fjernet fordi det introduserte en annen feil.
Merk fra typens vedlikeholder:
Imidlertid setter ikke TS typen til nyoppsatte defaultProps (også kalt expando), så ikke forvent at det vil tillate å hoppe over obligatoriske props. For å endre typen, la jeg til en enkel hjelpefunksjon i testene som setter defaultProps og returnerer endret type. Dette er ment å være kun et eksempel.
Her er det eksempelet:
// example of a simple helper that sets defaultProps and update the type
type WithDefaultProps<C, D> = C & { defaultProps: D };
function withDefaultProps<C, D>(component: C, defaultProps: D): WithDefaultProps<C, D> {
(component as WithDefaultProps<C, D>).defaultProps = defaultProps;
return component as WithDefaultProps<C, D>;
}
Denne hjelperen løser problemet (og er lik @TitianCernicova-Dragomirs tilnærming, så du bør vurdere å merke svaret hans som korrekt hvis du aksepterer dette som en korrekt løsning).
/* setup */
interface Props {
requiredProp: number;
}
const defaultProps: Props = {
requiredProp: 1,
};
const Component = styled.div<Props>``;
const ComponentWithDefault = withDefaultProps(Component, defaultProps);
export { Component, ComponentWithDefault };
/* usage */
import { Component, ComponentWithDefault } from './component.tsx';
const a = <Component /> // Property requiredProp is missing...
const b = <ComponentWithDefault /> // no error
Krav :
"@types/styled-components": "^4.1.12",
"typescript": "^3.2.4",
defaultProps med styled-components fungerte tidligere — hvis du er interessert i å beholde den oppførselen, tror jeg det kan hjelpe å gå tilbake til en eldre versjon av @types/styled-components; jeg tror det er 4.1.8, men jeg er ikke sikker.
Opprinnelig svar
Kanskje ikke svaret du leter etter, men jeg synes denne oppførselen er ønskelig. Hvis du allerede har definert visse egenskaper i defaultProps, vil ikke det gjøre disse egenskapene valgfrie?
Jeg ville gjort standardpropper valgfrie:
interface ButtonProps {
size?: 'small' | 'medium' | 'large';
inverted?: boolean;
raised?: boolean;
}
Eller behold det intakt, men pakk det inn i Partial<> siden du allerede gir standard for alle dem
const Button = styled('button')<Partial<ButtonProps>>`...`
En annen ting jeg vanligvis gjør er å definere defaultProps først i en variabel, slik at jeg kan definere grensesnittet deres på riktig måte:
interface Props { ... }
const defaultProps: Props = { ... }
const Component = styled.div<Props>`...`
Component.defaultProps = defaultProps
Svar #2
Problemet er at å tildele defaultProps ikke vil endre typen, som forblir standarden Partial<StyledComponentProps<"button", any, ButtonProps, never>>. Du kan eksplisitt angi typen for const, men det er aldri morsomt å skrive mange typer. En enklere tilnærming er å bruke en annen HOC (alt kan løses med en annen HOC 😃) som endrer typen til defaultProps slik at den inneholder de standardpropene du faktisk setter på komponenten:
// Button.ts
interface ButtonProps {
size: 'small' | 'medium' | 'large';
inverted: boolean;
raised: boolean;
}
function withDefault<T extends { defaultProps?: Partial<TDefaults> }, TDefaults>(o: T, defaultProps: TDefaults): T & { defaultProps: TDefaults } {
o.defaultProps = defaultProps;
return o as any;
}
const Button = withDefault(styled('button') <ButtonProps>`...`, {
size: 'medium',
inverted: false,
raised: false,
})
export default Button
const Hello = () => <Button>Hello</Button> // OK now
