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

Posted

技术标签:

【中文标题】如何使用 Typescript 在不丢失任何道具的情况下键入样式组件?【英文标题】:How to type a styled component without losing any prop with Typescript? 【发布时间】:2019-08-05 20:04:53 【问题描述】:

我是样式化组件的新手,我希望能够正确输入样式化组件,这样当我传递“vs code”道具时,我可以自动检测我拥有的所有道具,而不仅仅是主题中的那个或者我可以用接口放置的那些。

我在其他answer 中看到的那样,如果不使用 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;
`;

提前致谢, 最好的

【问题讨论】:

【参考方案1】:

出于某种原因(可能是由于styled-components 的打字稿定义的编写方式),如果您删除其中一个嵌套级别,Theme 的打字工作。这个 sn-p 类型检查对我来说没有错误(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,谢谢你的回答,但是有了这个道具的实现,你不会失去关于样式化组件或反应的其他属性吗?因为您减少了仅具有主题属性或您输入的自定义属性的可能性? 还有... 是否可以一次调用附件来使用它们?提前致谢!【参考方案2】:

这可以像@Huy-Nguyen 所说的那样解决,但实际上,您会丢失样式组件的属性,或者您必须多次定义相同的属性。

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

主题.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;
`;

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

非常感谢大家。

【讨论】:

【参考方案3】:

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

定义您的主题类型。

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

【讨论】:

我发誓这种方法一直对我有用。但是我正在处理的当前项目中的某些内容有所不同,我在props 上看到的所有类型都是any。我唯一不同的是我使用的是StyledComponentsThemeProvider。你有什么想法为什么我只是在道具上得到任何东西?【参考方案4】:

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

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

【讨论】:

以上是关于如何使用 Typescript 在不丢失任何道具的情况下键入样式组件?的主要内容,如果未能解决你的问题,请参考以下文章

在没有道具的 Typescript 中使用 React.forwardRef

修复“‘组件’没有任何构造或调用签名。” Typescript 的默认道具错误

如何在传递道具时使用 TypeScript 实现“as”道具?

如何使用 Typescript 扩展 Material-UI 组件的道具?

如何在不丢失 SQL 中的任何行的情况下合并两个表?

如何在不丢失或复制任何记录的情况下移动或更改管道