string 类型不可分配给字符串文字

Aly*_*ona 5 typescript

我想使用来自 的字符串文字typescript。我的界面:

interface Props {
   size: 'small' | 'medium' | 'large';
   count: number;
}
Run Code Online (Sandbox Code Playgroud)

然而我遇到了两个问题:

  1. 使用破坏时出错

如果我的数据在对象中

const data = {
  size: 'small',
  count: 36,
};
Run Code Online (Sandbox Code Playgroud)

然后当尝试解构它时,<Component {...data}>我收到以下错误:

Type 'string' is not assignable to type '"small" | "medium" | "large"'
Run Code Online (Sandbox Code Playgroud)
  1. 使用环境变量

我使用环境变量得到完全相同的错误:

size = process.env.SIZE; // while having SIZE = 'small'; in my .env file
Run Code Online (Sandbox Code Playgroud)

有人可以帮我提供如何修复这些问题的建议吗?高度赞赏。

T.J*_*der 5

前言:我会为联合定义一个类型别名,这样您就可以在多个地方使用它:

type Size = "small" | "medium" | "large";
Run Code Online (Sandbox Code Playgroud)

用这个名字...

回复 #1:问题是,尽管您已使用"small"的值data.size,但它可以被任何其他字符串覆盖。它的类型是string,而不是Size( "small" | "medium" | "large")。"small" | "medium" | "large"不过,您可以通过为对象定义类型并将其应用于常量来告诉 TypeScript 它是data

// Inline, or use `type` to define it separately
const data: Props  = {
//          ^^^^^
  size: 'small',
  count: 36, // I've assumed the `number: 36` in the question is a typo
};
Run Code Online (Sandbox Code Playgroud)

...或通过类型断言:

const data  = {
  size: "small" as Size,
//             ^^^^^^^^
  count: 36,
};
Run Code Online (Sandbox Code Playgroud)

或者,如果data永远不会改变,你可以as const这样说:

const data  = {
  size: "small",
  count: 36,
} as const;
//^^^^^^^^
Run Code Online (Sandbox Code Playgroud)

关于#2,环境变量可以是任何东西,所以通常你会使用类型断言函数:

function assertValidSize(size: string): size is Size {
    switch (size) {
        case "small":
        case "medium":
        case "large":
            return;
        default:
            throw new Error(`Invalid 'Size' value "${size}"`);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后:

const envSize = process.env.SIZE;
assertValidSize(envSize);
data.size = envSize;
Run Code Online (Sandbox Code Playgroud)

有几种方法可以实现这一点(使用类型保护函数而不是断言函数等),但这就是基本思想。


在您提出的评论中:

是否可以在不手动遍历案例的情况下为环境变量创建断言函数?就像从类型本身获取值并循环它们一样?

如果您从类型开始,则不会,但您可以从有效大小的常量数组开始,然后基于该常量数组派生类型和类型断言函数(和/或类型保护函数):

// The valid sizes
const sizes = ["small", "medium", "large"] as const;

// The type for an entry in `sizes`
type Size = typeof sizes[number]; // Ends up being `"small" | "medium" | "large"

// A type assertion function for a valid size
function assertValidSize(size: string): asserts size is Size {
    if (!(sizes as [string, string, string]).includes(size)) {
        throw new Error(`Invalid Size value "${size}"`);
    }
}

// Using it with `process.env.SIZE`:
assertValidSize(process.env.SIZE);
let size: Size = process.env.SIZE;
Run Code Online (Sandbox Code Playgroud)

on告诉as constTypeScriptsizes它的内容不会改变,这让 TypeScript

游乐场链接