使用该组件时,定义为defaultProps
的必需道具会丢失。
// 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>
按钮以红色突出显示,并显示以下错误消息:
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.
版本:
"@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",
答案 0 :(得分:2)
编辑虽然我个人对此行为很满意,但这与正常的React组件(typescript supports defaultProps
)的行为不一致。
我四处张望,似乎此问题已在@types/styled-components
中解决,但随后在removed due to it introducing another bug中解决了。
类型维护者的注意事项:
但是,TS不会设置新设置的defaultProps(又名expando)的类型,因此不要指望它会跳过必需的道具。 为了修改类型,在测试中,我添加了一个简单的帮助器函数,该函数设置defaultProps并返回修改后的类型。这仅是示例。
这里是example:
// 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>;
}
此帮助程序确实可以解决问题(并且类似于@TitianCernicova-Dragomir's approach,因此,如果您接受此正确的解决方法,则应考虑将其答案标记为正确)。
/* 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
要求:
"@types/styled-components": "^4.1.12",
"typescript": "^3.2.4",
带有样式组件的 defaultProps
在过去确实可行-如果您有兴趣保持这种行为,我认为恢复为旧版本的@ types / styled-components可能会有所帮助;我认为是4.1.8,但不确定。
原始答案
也许不是您要找的答案,但是我发现这种行为是可取的。
如果您已经在defaultProps
中定义了某些属性,那是否会使这些属性成为可选属性?
我将默认道具设为可选:
interface ButtonProps {
size?: 'small' | 'medium' | 'large';
inverted?: boolean;
raised?: boolean;
}
或者保持原样,但要包装Partial<>
,因为您已经为所有它们提供了默认值
const Button = styled('button')<Partial<ButtonProps>>`...`
我通常要做的另一件事是首先在变量中定义defaultProps
,这样我就可以正确定义它们的接口:
interface Props { ... }
const defaultProps: Props = { ... }
const Component = styled.div<Props>`...`
Component.defaultProps = defaultProps
答案 1 :(得分:2)
问题在于分配defaultProps
不会更改其类型,而其类型仍为默认的Partial<StyledComponentProps<"button", any, ButtonProps, never>>
。您可以显式地键入const
,但是键入很多类型从来都不是一件好事。一种更简单的方法是使用另一种HOC(可以用另一种HOC来解决所有问题),该HOC会改变defaultProps
的类型以包含您实际在组件上设置的默认props:
// 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
答案 2 :(得分:1)
应用功能道具的一种更可靠的方法是使用功能组合。
function withDefaults<T extends React.ComponentType<any>, U extends Partial<React.ComponentProps<T> & JSX.IntrinsicAttributes>>(Component: T, defaults: U): React.FC<Omit<React.ComponentProps<T>, keyof U> & Partial<U>> {
return props => React.createElement(Component, { ...defaults, ...props });
}
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
用法:
const ButtonWithDefaults = withDefaults(Button, {
size: 'medium',
inverted: false,
raised: false,
});
() => (
<ButtonWithDefaults>
Hello
</ButtonWithDefaults>
);
它可以实现一切:
as any
断言答案 3 :(得分:0)
一种更简单更好的解决方案是在销毁时在渲染(或使用它们的位置)中指定默认值,我经常这样做,这是一个示例:
// Button.ts
interface ButtonProps {
size?: 'small' | 'medium' | 'large'; // making optional via '?' sign
inverted?: boolean;
raised?: boolean;
}
render() {
const { size = 'medium', inverted = false, raised = false } = this.props;
// Use these props, if none are passed by user, these defaults will be used
// otherwise user versions will be used
}
答案 4 :(得分:0)
您可以只创建一个常规组件,然后将该组件的引用传递给style并像设置标签一样设置样式
const PlainButton = props: ButtonProps => (/* your jsx here */);
const Button = styled(PlainButton)`
color: #A5FFA5;
`;