Using styled components with props and typescript

后端 未结 4 1981
眼角桃花
眼角桃花 2021-02-01 20:24

I\'m trying to integrate typescript into our project and so far I stumbled upon one issue with styled-components library

Consider this component

import *         


        
相关标签:
4条回答
  • 2021-02-01 20:43

    There have been some recent developments and with a new version of Typescript (eg. 3.0.1) and styled-components (eg. 3.4.5) there's no need for a separate helper. You can specify the interface/type of your props to styled-components directly.

    interface Props {
      onPress: any;
      src: any;
      width: string;
      height: string;
    }
    
    const Icon = styled.Image<Props>`
      width: ${p => p.width};
      height: ${p => p.height};
    `;
    

    and if you want to be more precise and ignore the onPress

    const Icon = styled.Image<Pick<Props, 'src' | 'width' | 'height'>>`
      width: ${p => p.width};
      height: ${p => p.height};
    `;
    
    0 讨论(0)
  • 2021-02-01 20:43

    I'm struggling through this myself, but I think the problem is that you are using the Props interface inside the styled component. Try creating another interface with just the image props and use that in your styled component:

    import * as React from "react";
    import styled from "styled-components/native";
    import { TouchableOpacity } from "react-native";
    
    // -- types ----------------------------------------------------------------- //
    export interface Props {
      onPress: any;
      src: any;
      width: string;
      height: string;
    }
    
    
    export interface ImageProps {
      src: string;
      width: string;
      height: string;
    }
    
    // -- styling --------------------------------------------------------------- //
    const Icon = styled.Image`
      width: ${(p: ImageProps ) => p.width};
      height: ${(p: ImageProps ) => p.height};
    `;
    
    class TouchableIcon extends React.Component<Props> {
      // -- default props ------------------------------------------------------- //
      static defaultProps: Partial<Props> = {
        src: null,
        width: "20px",
        height: "20px"
      };
    
      // -- render -------------------------------------------------------------- //
      render() {
        const { onPress, src, width, height } = this.props;
        return (
          <TouchableOpacity onPress={onPress}>
            <Icon source={src} width={width} height={height} />
          </TouchableOpacity>
        );
      }
    }
    
    export default TouchableIcon;
    

    Seems to work but I hate to have to duplicate those interfaces. Hopefully someone else can show the correct way or maybe embedding the ImageProps into Props?

    0 讨论(0)
  • 2021-02-01 20:46

    This answer is outdated, the most current answer is here: https://stackoverflow.com/a/52045733/1053772

    As far as I can tell there is no official way (yet?) to do this, but you can solve it with a bit of trickery. First, create a withProps.ts file with the following content:

    import * as React from 'react'
    import { ThemedStyledFunction } from 'styled-components'
    
    const withProps = <U>() => <P, T, O>(fn: ThemedStyledFunction<P, T, O>) =>
        fn as ThemedStyledFunction<P & U, T, O & U>
    
    export { withProps }
    

    Now, inside your .tsx files, use it like this:

    // ... your other imports
    import { withProps } from './withProps'
    
    export interface IconProps {
      onPress: any;
      src: any;
      width: string;
      height: string;
    }
    
    const Icon = withProps<IconProps>()(styled.Image)`
      width: ${(p: IconProps) => p.width};
      height: ${(p: IconProps) => p.height};
    `;
    

    And you should be good to go. It's definitely not ideal and hopefully there will be a way to provide generics to template literals soon in TS, but I guess that for now this is your best option.

    Credit is given where credit is due: I copypasted this from here

    0 讨论(0)
  • 2021-02-01 20:49

    You need only specify a interface:

    import { createGlobalStyle } from 'styled-components';
    
    interface PropsGlobalStyle {
      dark: boolean
    }
    
    export default createGlobalStyle`
      body {
        box-sizing: border-box;
        margin: 0;
        font-family: Arial, Helvetica, sans-serif;
        color: ${(props:PropsGlobalStyled) => (props.dark ? '#FFF' : '#000')};
    background-color: ${(props:PropsGlobalStyled) => (props.dark ? '#000' : '#FFF')};
      }
    `;
    
    0 讨论(0)
提交回复
热议问题