我可以确定一个值是否与类型别名匹配吗?

Can I determine if a value matches a type alias?

在 TypeScript 中,我可以确定一个值 is/matches 是否是类型别名吗?

假设我有这种类型:

export type Name = "Jane" | "John";

然后在其他地方我想检查某个用户输入是否属于 Name 类型。 if (input instanceOf Name) 之类的东西不起作用。

这可能吗?

不,在运行时这些信息不存在,因此不能用于此类用例。

TypeScript 是结构类型语言。这意味着当你创建一个类型时,在左边你有一个名字,而在右边你有在运行时的精确类型表示。这里没有像在名义类型系统中那样的额外魔法(类 和枚举是例外)。

这意味着为了检查某些东西是否具有这种类型,我们需要进行显式检查或编写辅助函数来检查它。

function isName(a: unknown): a is Name {
  return a === "Jane" || a === "John";
}

可能看起来比较繁琐,但一般来说如果做union类型的话,选项的数量应该是合理的。如果选项量真的很大,可能是数据模型不对,需要重新考虑是否需要这样的union。

您无法检查值是否与类型别名匹配。类型在运行时被擦除,因此任何运行时代码都不能依赖于它们。

如果您控制类型别名,我会建议创建一个数组来保存值,让 TS 为其推断类型,并从中派生联合。然后你可以检查一个值是否在数组中:

const Name = ["Jane", "John"] as const
export type Name = typeof Name[number];

function isName(a: unknown): a is Name {
    return Name.indexOf(a as Name) != -1;
}

Playground Link

到目前为止,我所知道的唯一方法是从 const 数组生成类型别名,然后根据该数组检查您的名字。

const names = ["Jane", "John"] as const;
type Name = typeof names[number];

function isValidName(name: string): name is Name {
    return names.includes(<Name> name);
}

用法:

const test: string = "John";
if (isValidName(test)) {
    console.log(`${test} is a name`);
}
else {
    console.log(`${test} is not a name`);
}

我仍然不明白为什么打字稿不能从类似

的东西编译
type Example = 'first' | 'second';
const exampleValues = [typeof Example] as const;

const exampleValues = ['first', 'second'];

答案 AFAIK 是“类型在运行时被擦除”,但是将类型别名编译为文字数组在运行时不需要类型信息。

  1. 它没有任何开销
  2. 保留 javascript
  3. 的运行时行为
  4. 并且不提供额外的运行时功能

这将允许开发人员在运行时通过在数组中查找值来验证字符串。

如果有办法做到这一点,请告诉我。 正如我所展示的,您可以执行相反的操作,从数组到类型别名,但是使用类型别名您可以过滤和组合类型,我有兴趣在编译时从类型别名转换为数组.