Typescript:检查值是否包含在类型中

41

我遇到了有关定义类型和检查值是否包含在该类型中的问题。

这是我的示例:

以下是各种类型:

export type Key = 'features' | 'special';

export type TabTypes = 'info' | 'features' | 'special' | 'stars';

当用户更改选项卡时,它会发送一个字符串值,其类型为TabTypes。
activeTabChanged(event: TabTypes) {
    this.activeTab: TabTypes = event;
    // it won't let me set the key here because key has a different type 
    // but the send event can be contained in type Key
    // how can I check if the send event from type TabTypes is contained in type Key
    this.key: Key = event;
}

有没有一种TypeScript的方法可以检查一个具有类型的发送值是否可以等于来自不同类型的值?
5个回答

26

2019年解决方案:

我有同样的需求,并在另一个帖子中找到了更简单的方法。总结一下,在那个链接中Patrick Roberts所说的(使用这个问题的值进行更新)是:“不要过度复杂化。”

不要过度复杂化。

function isOfTypeTabs (keyInput: string): keyInput is TabTypes {
  return ['info', 'features', 'special', 'stars'].includes(keyInput);
}

请参考什么是TypeScript中的is关键字?以获取更多信息,了解为什么我们不仅仅使用布尔值作为返回类型。

此处列出全部来源及鸣谢:https://dev59.com/ODgCtIcB2Jgan1znqCx3#57065680


5

您可以使用字符串枚举。

export enum Keys = {
  Features = 'features',
  Special = 'special',
}

// Compare it
if (currentKey === Keys.Special) { console.log('Special key is set'); }

为了检查预定义枚举中是否定义了您的值,您可以执行以下操作:
if (currentKey in Keys) { console.log('valid key'); }

1
currentKey in Keys 只适用于数字枚举,无法用于字符串枚举。 - Maor Refaeli
2
正如@MaorRefaeli所说,使用currentKey in Keys根本不起作用。这个问题为什么会有赞成票很奇怪,因为如果你尝试这样做,它是行不通的。我花了好15分钟重构我的代码,结果当我运行代码时它却不起作用。 - KG23

2
这篇答案可能对你有用。虽然它并没有直接回答你的问题,但是它展示了一种类似的实现方式。
简而言之,你可以使用数组进行包含性检查,并使用类型保证类型安全:
const keys = <const> ['features','special'];
export type Key = typeof keys[number];
const tabTypes = <const> ['info' ,'features' ,'special', 'stars'];
export type TabTypes = typeof tabTypes[number];

activeTabChanged(event: TabTypes) {
    this.activeTab: TabTypes = event;
    // it won't let me set the key here because key has a different type 
    // but the send event can be contained in type Key
    // how can I check if the send event from type TabTypes is contained in type Key

    if (event in keys) {
        this.key: Key = event as Key;
    }
}

0
const TabValues = ['info', 'features', 'special', 'stars'] as const;
const TabValuesObj = TabValues.reduce(
  (acc, next) => ({ ...acc, [next]: null }),
  {} as Record<string, null>,
);
export type TabType = typeof TabValues[number];
export function isTabType(value: string): value is TabType {
  return value in TabValuesObj;
}

这里有一个选项,应该能够允许非常快速的验证,即使类型中有大量的选项。

-1
虽然 Array.includes 可以工作,但它具有线性时间复杂度。假设您的选项卡类型列表是唯一的(使用带有重复值的联合类型并不真正有意义),使用 Set 更快。
const tabsSet = new Set(['info', 'features', 'special', 'stars'])
const isOfTypeTabs = (keyInput: string): boolean => tabsSet.has(keyInput)

console.log(isOfTypeTabs('info')) // true
console.log(isOfTypeTabs('foo')) /

2
这是过早优化的典型例子。除非数组中有大量元素,否则数组实际上更快。这是因为缓存局部性超过了线性时间复杂度。 - Marko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接