首页 > 解决方案 > 从 React 组件中导出 TypeScript 类型的字符串属性值?

问题描述

我有一个 React / TypeScript 组件。在 Button.tsx 中:

type Props = {
  type: 
    | "primary"
    | "secondary"
    | "tertiary"
}

const Button = React.FC<Props> = ({ type }) => {
    const color = (() => {
        switch (type) {
          case "primary":
            return 'red';
          case "secondary":
            return 'blue';
          case "tertiary":
            return 'green';
          default:
            throw new Error("A backgroundColor condition was missed");
        }
    })();

    return(
        <button style={{ background: color }}>Im a button</button>
    )
}

我可以在其他组件中使用它。在 Page.tsx 中:

const Page = () => {
    return(
        <div>
            <h1>Heading</h1>
            <Button type="primary" />
        </div>
    )
}

在 Storybook 中,我需要使用所有类型值。在 Button.stories.js 中:

const types = [
  "primary",
  "secondary",
  "tertiary",
];

export const AllButtons = () => {
    return(
        types.map(type=>{
            <Button type={type} key={type} />
        })
    )
}

不必重复“主要”、“次要”、“第三级”,有没有办法可以从 Button.tsx 导出它们?这样,如果添加了新类型,Storybook 文件将自动拥有它。

我可以在 Button.tsx 中使用枚举:

export enum Types {
  primary = "primary",
  secondary = "secondary",
  tertiary = "tertiary",
}

type Props = {
  type: Types;
};

但是,使用 Button 的组件不能只传递一个字符串,每次使用 Button 时都必须导入枚举,这是不值得的。在 Page.tsx 中:

import { Type } from './Button'

const Page = () => {
    return(
        <div>
            <h1>Heading</h1>
            <Button type={Type.primary} />
        </div>
    )
}

标签: typescript

解决方案


在 TypeScript 中,您可以从值中获取类型(使用typeof),但永远无法从类型中获取值。所以如果你想消除重复,你需要使用一个值作为你的真实来源,并从中派生出类型。

例如,如果您将按钮类型数组作为事实来源,那么您可以使用const 断言( as const) 从中派生类型:

// Button.tsx
export const BUTTON_TYPES = [
    "primary",
    "secondary",
    "tertiary",
] as const;

type Types = typeof BUTTON_TYPES[number];

type Props = {
    type: Types;
}

const Button: React.FC<Props> = ({ type }) => {
    // ...

    return(
        <button style={{ background: color }}>Im a button</button>
    )
}

然后您可以导入BUTTON_TYPES您的故事并对其进行迭代。

您还可以制作从按钮类型到颜色的映射,并将其用作您的真实来源。这将使您color从组件中消除该功能:

const TYPE_TO_COLOR = {
  primary: 'red',
  secondary: 'blue',
  tertiary: 'green',
} as const;

type Types = keyof typeof TYPE_TO_COLOR;
// type Types = "primary" | "secondary" | "tertiary"
export const BUTTON_TYPES = Object.keys(TYPE_TO_COLOR);

type Props = {
  type: Types;
}

const Button: React.FC<Props> = ({ type }) => {
  const color = TYPE_TO_COLOR[type];
  if (!color) {
    throw new Error("A backgroundColor condition was missed");
  }

  return (
    <button style={{ background: color }}>Im a button</button>
  );
}

推荐阅读