如何在 TypeScript 中迭代自定义文字类型?

Posted

技术标签:

【中文标题】如何在 TypeScript 中迭代自定义文字类型?【英文标题】:How can I iterate over a custom literal type in TypeScript? 【发布时间】:2017-04-13 07:23:17 【问题描述】:

我在 TypeScript 中定义了一个自定义文字类型:

export type Market = 'au'|'br'|'de';

现在我想遍历每个可能的 Market 而不必首先创建一个 Market[] 数组,因为它感觉多余,我可能会忘记添加一个选项:

const markets: Market[] = ['au', 'br', 'de'];
markets.forEach((market: Market) => 
    console.log(market);
);

有没有办法使用 TypeScript 来实现?

【问题讨论】:

这是不可能的,但我真的希望 TS 团队在类型中添加类似自省的东西,在运行时可用。 类型别名(和接口)的全部意义在于它们不会被编译成 javascript。如果你只想要编译的东西,那么你可以使用它,但如果你需要它用于运行时,那么你必须使用 js 中存在的东西。 【参考方案1】:

对于那些使用 TypeScript >= 3.4 访问此问题的人,我相信现在最好的做法是创建一个字符串常量数组,然后使用运算符的类型。

例子:

export const markets = ['au', 'br', 'de'] as const;
export type Market = typeof markets[number];

markets.forEach((market: Market) => 
    console.log(market);
);

【讨论】:

谢谢 :-) as const 是什么意思? 它告诉 Typescript 它是不可变的。 typescriptlang.org/docs/handbook/release-notes/… 在这种情况下,Market 类型等于string(而不是'au'|'br'|'de')。这不是违背了目的吗? @scale_tone - 不正确。市场类型不等于string。 ` const 市场 = ['au', 'br', 'de'] 作为 const;市场类型=市场类型[数量];常量测试:市场='测试';类型 '"test"' 不能分配给类型 '"br" | “非” | “德”。 ` @keithhackbarth,确实如此。我一定是被 vscode 的提示给骗了。【参考方案2】:

我认为最容易理解的 TypeScript 3.9 的完整示例:

enum SupportedLangugesEnum 
    'au' = 'au',
    'br' = 'br',
    'de' = 'de',


for (let entry in SupportedLangugesEnum) 
    if (isNaN(Number(entry))) 
        console.log(entry);
    


for (let entry of Object.keys(SupportedLangugesEnum)) 
    console.log(entry);


for (let entry of Object.values(SupportedLangugesEnum)) 
    console.log(entry);

将打印:

来源:

https://***.com/a/39372911/3850405

【讨论】:

【参考方案3】:

这是另一种方式:

enum Market 
   'eu' = 'eu',
   'us' = 'us',


const all_possible_market_values = getStringValuesFromEnum(Market)

function getStringValuesFromEnum<T>(myEnum: T): (keyof T)[] 
   return Object.keys(myEnum) as any

基础表示不再是数字。这是字符串。

"use strict";
var Market;

(function (Market) 
    Market["eu"] = "eu";
    Market["us"] = "us";
)(Market || (Market = ));

const all_possible_market_values = getStringValuesFromEnum(Market);

function getStringValuesFromEnum(myEnum) 
    return Object.keys(myEnum);

【讨论】:

【参考方案4】:

以下是我要创建一个数组,该数组在运行时包含所有值并在编译时进行检查:

export type Market = 'eu' | 'us'

export const MARKET_TYPES: Market[] = (() => 
   const markets: Market[] = ['eu', 'us']

   return markets.map((x: Market) => 
      if (x === 'eu') 
         return x
       else if (x === 'us') 
         return x
       else 
         const _exhaustive_check: never = x
         return _exhaustive_check
      
   )
)()

【讨论】:

你的地图不是总是返回x吗?我看不出您的地图与此地图有何不同:.map((x: Market) =&gt; x) 我不会否决这个答案。我相信其目的是表明您可以创建一个类型,然后创建一个可用类型的数组以进行迭代。你用它做什么在 map 方法中是任意的。我真的很喜欢看到详尽的检查,更多的打字稿开发人员需要这样做。 +1【参考方案5】:

不,你不能这样做,因为像这样的纯类型信息在运行时不存在。

假设另一种方式是合理的(定义一个普通的字符串列表,然后从中派生 'au'|'br'|'de' 类型),但我认为 TypeScript 编译器(2.0 或 2.1)目前不会推断出对你来说——据我所知,市场类型通常总是string[]

对此的正确答案是使用枚举。他们为每个值定义了一个类型,并且可以获得所有字符串值的列表:How to programmatically enumerate an enum type in Typescript 0.9.5?。

枚举的一个缺点是它们的运行时表示不同(实际上它们是数字,而不是字符串)。您的代码仍然可以将它们视为很好的可读值,只是如果您在运行时需要它们作为字符串名称,则必须将它们转换为字符串。不过这很简单:给定枚举 MarketEnum 和值 myEnumValueMarketEnum[myEnumValue] 是值的名称作为字符串)。

【讨论】:

以上是关于如何在 TypeScript 中迭代自定义文字类型?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 TypeScript 中指定定义为对象文字的箭头函数的类型?

如何从 Typescript 中的常量定义字符串文字联合类型

TypeScript 如何知道自定义数组类型中长度字段的行为?

如何在 TypeScript 中创建自定义类型

如何在 Vue Router v4 中为自定义元字段声明 TypeScript 类型接口?

如何在 TypeScript 中构建自定义的必需接口?