类型 'string' 不能赋值给类型 'SOME TYPE',传递 props 时的小混乱

Type 'string' is not assignable to type 'SOME TYPE', small confusion when passing props

下面是我如何使用我制作的可重用组件 Badge。它具有如下道具类型,但这会产生某种错误:

这是完整的代码,

const variantsMap = {
  done: "success",
  processing: "info",
  suspened: "warning",
  cancelled: "error",
};

interface ITransactionProps {
  status: "done" | "processing" | "suspened" | "cancelled";
  label: string;
}

const MyComponent = ({ status, label }: ITransactionProps) => {
  return <Badge variant={variantsMap[status]}>{label}</Badge>;
};

interface IBadgeProps {
  variant: "success" | "info" | "warning" | "error";
  children: string;
}

const Badge = ({ variant, children }: IBadgeProps) => {
  return <div className={`badge bordered circular ${variant}`}>{children}</div>;
};

如何正确解决这个问题?我想知道所有的方法,如果我们可以通过多种方式解决它。

您可以声明 variantsMap 有点不同

const variantsMap: Record<string, "success" | "info" | "warning" | "error"> = ...

为了便于阅读,我会将其提取为新类型。

type Variant = "success" | "info" | "warning" | "error";

const variantsMap: Record<string, Variant> = ...

interface IBadgeProps {
  variant: Variant;
  children: string;
}

一个很好的简单干净的解决方案是使用 as const:

const variantsMap = {
  done: "success",
  processing: "info",
  suspened: "warning",
  cancelled: "error",
} as const;

现在 variantsMap 输入为:

{
    readonly done: "success";
    // ...
}

这意味着访问属性会导致文字类型,而不是 string 这是错误的原因。

这是一种方法:TypeScript Playground

完整代码如下所示:

import React from 'react';

type Variant = "done" | "processing" | "suspened" | "cancelled";

const variantsMap: Record<Variant, string> = {
  done: "success",
  processing: "info",
  suspened: "warning",
  cancelled: "error",
};

interface ITransactionProps {
  status: Variant;
  label: string;
}

const MyComponent = ({ status, label }: ITransactionProps) => {
  return <Badge variant={variantsMap[status]}>{label}</Badge>;
};

interface IBadgeProps {
  variant: string;
  children: JSX.Element | string;
}

const Badge = ({ variant, children }: IBadgeProps) => {
  return <div className={`badge bordered circular ${variant}`}>{children}</div>;
};