TypeScript with styled-components

六眼飞鱼酱① 提交于 2020-04-08 09:51:47

问题


TypeScript newbie here. I have a below component using styled-components that I would like to convert to 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

I know I can replace my propTypes with an interface

interface Props {
  name: string
}

However, TypeScript complains that I leave className undeclared. The thing is, I would ideally like to use the interface as a sort of spec for props that a developer can provide, without having to declare props like className or theme which are injected by libraries like styled-components.

How do I properly convert this component to TypeScript?


回答1:


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;

As per the styled-components TypeScript docs: when defining a component you will need to mark className as optional in your Props interface




回答2:


There are many things happening here.

props.theme is not going to typed properlly unless you have the internal type for Theme augmented somewhere like this....

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

This will change the type of props.theme to YourThemeInterfaceType, if you follow the augmentation documentation properlly but if you can't just create a styled-components.d.ts file and this to your tsconfig.

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

Next you need the type of the arguments to know "name" is a string, and className is also i'm assuming a optional string to do this just rewrite the above to this.

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.

Hope this helps.

EDIT: also proptypes are usless in typescript.




回答3:


Here's a comprehensive approach using Styled Components v5 with React Native that will work with plain React as well. If you're not using a theme you can skip to the StyledProps section at the bottom.

  • Define your theme type.

    // MyTheme.ts
    
    export type MyTheme = {
      colors: {
        primary: string;
        background: string;
      };
    };
    
  • Use the type on your themes.

    // themes.ts
    
    export const LightTheme: MyTheme = {
      colors: {
        primary: 'white',
        background: 'white',
      },
    };
    
    export const DarkTheme: MyTheme = {
      colors: {
        primary: 'grey',
        background: 'black',
      },
    };
    
  • Use declaration merging to "merge" the MyTheme type into Styled Components default theme.

    // 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 {}
    }
    

OK, cool. The theme prop is correctly typed.
What about the components themselves?

  • Wrap your specific component props in the StyledProps type.

    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}
      `,
    );
    

In this example both props.backgroundColor and props.theme.colors.background will auto-complete. When you update MyTheme type or the specific component type it should just work. 👍



来源:https://stackoverflow.com/questions/55412662/typescript-with-styled-components

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!