如何在不丢失 Typescript 的任何道具的情况下键入样式化的组件?

How to type a styled component without losing any prop with Typescript?

我是样式化组件的新手,我希望能够正确输入我的样式化组件,这样当我传递 props 时 "vs code" 我可以自动检测我拥有的所有这些 props,而不仅仅是一个在主题或我可以用界面放置的主题中。

有没有像我在其他 中看到的那样不使用 HOC 的方法?是否有可能得到一个通用的道具,而不必像示例中那样在每个 属性 样式中定义?

app.theme.ts

export const theme = {
  palette: {
    primaryColor: '#FF5018',
    secondaryColor: '#252729',
    tertiaryColor: '#1A1C1E',
    textColor: 'white',
  },
};

export type Theme = typeof theme;

navigation-bar.styled.component.ts

export const NavigationBarStyled = styled.div`
  grid-area: navigation-bar-item;
  padding-left: 2rem;
  display: flex;
  align-items: center;
  color: ${({ theme }) => theme.palette.primaryColor};
  background-color: ${({ theme }) => theme.palette.primaryColor};
`;

提前致谢, 最佳

出于某种原因(可能是由于 styled-components 的打字稿定义的编写方式),如果您删除其中一层嵌套,Theme 的打字仍然有效。这个片段类型检查对我来说没有错误(v4)即打字稿知道 primaryColorstring:

const theme = {
  primaryColor: '#FF5018',
  secondaryColor: '#252729',
  tertiaryColor: '#1A1C1E',
  textColor: 'white',
};

type Theme = typeof theme;

type Props = Theme & {
  // ... other keys
}

const NavigationBarStyled = styled.div<Props>`
  grid-area: navigation-bar-item;
  padding-left: 2rem;
  display: flex;
  align-items: center;
  color: ${props => props.primaryColor};
  background-color: ${props => props.primaryColor};
`;

它可以像@Huy-Nguyen 所说的那样解决,但在实践中,您会丢失 Styled Components 的属性,或者您必须多次定义相同的属性。

所以最好的选择是 Styled-Components 网站所说的(定义主题界面):

theme.ts

export default interface ThemeInterface {
  primaryColor: string;
  primaryColorInverted: string;
}

styled-components.ts

import * as styledComponents from "styled-components";

import ThemeInterface from "./theme";

const {
  default: styled,
  css,
  createGlobalStyle,
  keyframes,
  ThemeProvider
} = styledComponents as styledComponents.ThemedStyledComponentsModule<ThemeInterface>;

export { css, createGlobalStyle, keyframes, ThemeProvider };
export default styled;

然后,你使用那个:

import styled from 'app/styled-components';

// theme is now fully typed
const Title = styled.h1`
  color: ${props => props.theme.primaryColor};
`;

只需传递 link: https://www.styled-components.com/docs/api#define-a-theme-interface

非常感谢大家。

我们采用了不同的方法。
注意:Styled Components v5 with React Native

  • 定义您的主题类型。

    // 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 类型 "merge" 设置为 Styled Components 默认主题。

    // 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 类型或特定组件类型时,它应该可以正常工作。

不知道是不是最好的方法。但是我找到了如下解决方法。

// theme.ts
const theme = {
  colors: {
     ...
  }
};
export type themeTypes = typeof theme;
export default theme;


// styled.d.ts ( in root folder )
import 'styled-components'
import { themeTypes } from '@/styles/theme'

declare module 'styled-components' {
  // eslint-disable-next-line @typescript-eslint/no-empty-interface
  export interface DefaultTheme extends themeTypes {}
}