具有样式组件的TypeScript

时间:2019-03-29 07:44:48

标签: reactjs typescript styled-components

TypeScript新手。我有一个下面的组件要使用styled-components转换为TypeScript

import React from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components'


const propTypes = {
  name: PropTypes.string.isRequired // https://material.io/tools/icons/?style=baseline
}

const Icon = styled(({name, className, ...props}) => <i className={`material-icons ${className}`} {...props}>{name}</i>)`
  font-size: ${props => props.theme.sizeLarger};
`

Icon.propTypes = propTypes

export default Icon

我知道我可以将propTypes替换为interface

interface Props {
  name: string
}

但是,TypeScript抱怨我未声明className。问题是,理想情况下,我想将interface用作开发人员可以提供的道具规范,而不必声明classNametheme之类的道具,这些道具由styled-components之类的库。

如何正确地将此组件转换为TypeScript?

3 个答案:

答案 0 :(得分:4)

这是将样式化组件v5与React Native一起使用的一种综合方法,该方法也可以与普通React一起使用。如果您不使用主题,则可以跳到底部的StyledProps部分。

  • 定义主题类型。

    // MyTheme.ts
    
    export type MyTheme = {
      colors: {
        primary: string;
        background: string;
      };
    };
    
  • 在主题上使用类型。

    // themes.ts
    
    export const LightTheme: MyTheme = {
      colors: {
        primary: 'white',
        background: 'white',
      },
    };
    
    export const DarkTheme: MyTheme = {
      colors: {
        primary: 'grey',
        background: 'black',
      },
    };
    
  • 使用declaration merging将MyTheme类型“合并”为“样式组件”默认主题。

    // styled.d.ts
    
    import 'styled-components';
    import { MyTheme } from '../src/themes/MyTheme';
    
    declare module 'styled-components' {
      // eslint-disable-next-line @typescript-eslint/no-empty-interface
      export interface DefaultTheme extends MyTheme {}
    }
    

好的,很酷。 theme道具的类型正确。
组件本身如何?

  • StyledProps类型包装您的特定道具。

    import { StyledProps } from 'styled-components';
    import styled from 'styled-components/native';
    
    type MyViewProps = StyledProps<{
      backgroundColor?: string;
      isAlert?: boolean;
    }>;
    
    const MyView = styled.View(
      (props: MyViewProps) => `
        background-color: ${props.backgroundColor || props.theme.colors.background};
        color: ${props.isAlert ? red : props.theme.colors.primary}
      `,
    );
    

在此示例中,props.backgroundColorprops.theme.colors.background都将自动完成。更新MyTheme类型或特定组件类型时,它应该可以正常工作。 ?

component auto-complete

them auto-complete

答案 1 :(得分:2)

import React from "react";
import styled from "styled-components";

interface Props {
  name: string;
  className?: string;
}

const NonStyledIcon: React.SFC<Props> = ({ name, className, ...props }) => (
  <i className={`material-icons ${className}`} {...props}>
    {name}
  </i>
);

const Icon = styled(NonStyledIcon)`
  font-size: ${props => props.theme.sizeLarger};
`;

export default Icon;

根据样式化的组件TypeScript docs:定义组件时,您需要在Props界面中将className标记为可选

答案 2 :(得分:0)

这里发生了很多事情。

props.theme不会正确键入,除非您将Theme的内部类型扩展到这样的位置。...

declare module "styled-components" {
    /* tslint:disable */
    export interface DefaultTheme extends YourThemeInterfaceType {}
}

如果您正确地遵循了扩充文档,但是如果您不能只是创建一个styled-components.d.ts文件,并将其更改为tsconfig,则会将props.theme的类型更改为YourThemeInterfaceType。

"include": [
    "src/**/*"
],

接下来,您需要使用参数的类型来知道“名称”是一个字符串,并且className也是我假设的可选字符串,只需将上面的内容重写为此即可。

interface IIconProps {
    name: string;
    className?: string;
};

const Icon = styled(({name, className, ...props}: IIconProps) => <i className={`material-icons ${className}`} {...props}>{name}</i>)`
    font-size: ${props => props.theme.sizeLarger};
`;


const test = <Icon name={"xyz"} className={"xyz"}/> // passes typecheck.

希望这会有所帮助。

编辑:原型在打字稿中也没有用。