Экспорт значений типизированной строки TypeScript из компонента React? - PullRequest
2 голосов
/ 25 мая 2020

У меня есть компонент 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>
    )
}

Ответы [ 2 ]

1 голос
/ 29 мая 2020

В 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>
  );
}
1 голос
/ 27 мая 2020

Вы можете сгенерировать объявление объекта и объявить на его основе тип. Таким образом, вы сможете перебирать его ключи, и тип будет обновляться при каждом изменении.

Button.tsx

import * as React from "react";

export const ButtonSkins = {
  primary: "primary",
  secondary: "secondary",
  tertiary: "tertiary"
};

export type ButtonSkin = keyof typeof ButtonSkins;
export type ButtonProps = {
  skin: ButtonSkin;
};

export const Button: React.FC<ButtonProps> = ({ skin }) => (
  <button className={skin}>{skin}</button>
);

App.tsx (я поместил l oop сюда, но вы, конечно, можете использовать его в сборнике рассказов)

import * as React from "react";
import { render } from "react-dom";
import { Button, ButtonSkins, ButtonSkin } from "./Button";

const App = () => (
  <div>
    {(Object.keys(ButtonSkins) as Array<ButtonSkin>).map(skin => {
      return <Button skin={skin} />;
    })}
    <h2>Start editing to see some magic happen {"\u2728"}</h2>
  </div>
);

render(<App />, document.getElementById("root"));

https://codesandbox.io/s/recursing-browser-qkgzb?file= / src / index.tsx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...