styled-components defaultProps

8
如果我有以下带有默认属性的按钮:
export interface IButton {
  variant: 'action' | 'secondary';
}

export const Button = styled('button')<IButton>`
  background-color: #fff;

  ${props =>
    props.variant === 'action' &&
    css`
      color: blue;
    `};

  ${props =>
    props.variant === 'secondary' &&
    css`
      color: gray;
    `};
`;

Button.defaultProps = {
  variant: 'action',
};

有没有办法打字?当试图像这样使用它时:
<Button>Hello</Button>

Typescript提示没有传递variant,有没有一种方法使用styled-components对defaultProps进行类型定义?

这个问题已经过时了。现在可以使用StyledComponents + TypeScript + React来解决。请查看下面的答案。 - Beau Smith
5个回答

5
问题在于,TypeScript 3.0 在检查 JSX 元素的 defaultProps 支持方面需要在组件中声明 defaultProps 的类型。对现有组件的 defaultProps 进行更改是无效的,而且我不知道如何在由 styled 等函数生成的组件上声明 defaultProps(这在某种程度上是有道理的:库创建了一个组件,不希望您对其进行修改。也许库甚至为某些内部目的设置了 defaultProps)。kingdaro 的解决方案很好,或者您可以使用包装组件。
const Button1 = styled('button')<IButton>`
  background-color: #fff;

  ${props =>
    props.variant === 'action' &&
    css`
      color: blue;
    `};

  ${props =>
    props.variant === 'secondary' &&
    css`
      color: gray;
    `};
`;

export class Button extends React.Component<IButton> {
  static defaultProps = {
    variant: 'action'
  };
  render() {
    return <Button1 {...this.props}/>;
  }
}

如果我采用TS方法,它会抱怨onClick在内置属性类型上不存在。我有什么遗漏吗? - donzul
请将所有相关的代码添加到问题中,我会查看一下。(我没有看到使用onClick的地方。) - Matt McCutchen

4
你可以通过解构你的 props 来实现你想要的功能。
看起来你还需要让你的组件知道它的 prop 类型。为此,只需传递所有的 props 而不进行解构(请查看下面的背景颜色)。
import styled from "styled-components";

interface IProps {
  variant?: 'action' | 'secondary';
}

export const Button = styled.div`
  ${(props: IProps) => `background-color: #fff;`}
  ${({ variant = 'action' }) => variant === 'action' ? `color: blue;` : `color: gray;`}
`;

2
据我所知,目前还无法完全实现这一点,并且不幸的是,在TS 3.0中添加的defaultProps支持并不能覆盖所有情况(仅适用于普通组件类和我认为函数式组件)。如果我有误,请其他人随时纠正。
但是,还有其他方法可以实现。以下是我通常的做法:
export interface IButton {
  variant?: 'action' | 'secondary';
}

const variantStyles = {
  action: css`
    color: blue;
  `,
  secondary: css`
    color: gray;
  `,
};

export const Button = styled('button')<IButton>`
  background-color: #fff;
  ${props => variantStyles[props.variant || 'action']};
`;

1
截至2022年12月,原问题中的示例代码在使用React中的Styled Components时对我有效。
当我搜索指定默认StyleComponents主题的方法时,发现了这个问题。以下是我的做法:
interface ITheme {
  color: string;
}

const defaultTheme: ITheme = {
  color: 'blue';
}

interface IButton {
  theme?: Theme;
}

export const Button = styled('button')<IButton>`
  color: ${({ theme }) => theme.color};
`;

Prose.defaultProps = {
  theme: defaultTheme,
};

利用上述示例,我可以在使用或不使用StyledComponents ThemeProvider的情况下使用按钮。

使用ThemeProvider

<ThemeProvider theme={{ color: 'red' }}>
  <Button>I am a red button</Button>
</ThemeProvider>

没有 ThemeProvider:

<Button>I am a blue button</Button>

这里有一个相关的示例,虽然不是使用TypeScript,但在高级文档的“主题化”代码示例中有所体现:https://styled-components.com/docs/advanced#theming 此外,除非该示例是为了使用defaultProps而人为构造的,否则在问题的示例中有一种更简单的方法可以使用默认颜色,而无需使用defaultProps:
export interface IButton {
  variant: 'action' | 'secondary';
}

export const Button = styled('button')<IButton>`
  background-color: #fff;
  color: ${({ variant }) => (variant === 'secondary') ? 'gray' : 'blue' };
`;

0

对于大多数情况,我使用带有默认值的包装组件:

interface IProps {
    // not optional
    variant: 'action' | 'secondary';
}

const SButton = styled.button<IProps>`
    ...styles
`

// make optional
export const Divider = (props: Partial<IProps>) => {
    // set default value
    const { variant = 'action', ...rest } = props;

    // insert default value
    return <SButton variant={variant} {...rest}>{children}</SButton>;
};

最好将样式属性和主组件属性分开。
interface IProps extends Partial<IStyledProps> {
    // component props
}

// or if you have composed component with multiple styled components
interface IProps extends Partial<IStyledProps1>, Partial<IStyledProps2>, Partial<IStyledProps3> {
    // component props
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接