TypeScript中的类型化数组到文字类型

Posted

技术标签:

【中文标题】TypeScript中的类型化数组到文字类型【英文标题】:Typed Array to literal Type in TypeScript 【发布时间】:2021-12-18 11:36:56 【问题描述】:

typed 字符串数组如何根据实际值用作 literal 类型的联合?在高层次上,我有一个像 ['hello', 'world'] 这样的类型化数组,我想从中推断出一种新类型的 'hello' | 'world'

const someArray: Readonly<Array<string>> = ['hello', 'world'] as const;
type SomeType = typeof someArray[number]; // string

SomeType 现在将被推断为string 而不是联合。如何推断文字类型的联合?

这个问题与TypeScript array to string literal type 非常相似,不同之处在于数组是typed。我无法删除它。下面的代码可以工作,但someArray 实际上输入为Array&lt;string&gt;

const someArray = ['hello', 'world'] as const;
type SomeType = typeof someArray[number]; // 'hello' | 'world'

有没有办法相应地缩小推断类型?

edit:这个例子显然被简化了。我使用需要一组对象的第三方库。这些是由第三方键入的,如果不失去类型支持,我无法更改它。我意识到它可以在没有类型的情况下工作,但我无法真正删除它。

【问题讨论】:

这能回答你的问题吗? Typescript derive union type from tuple/array values 你已经找到了所有的答案——如果编译器必须继续运行的是string[],那么它显然没有创建联合的信息。 Readonly&lt;Array&lt;string&gt;&gt; 的优先级高于 as const @HarunYilmaz 不,它没有。我知道它可以在没有类型的情况下工作,但我无法实际删除它(请参阅我的编辑)。我的问题是是否以及如何使用 类型来完成。 它不能,添加类型显式覆盖编译推断的任何内容。您必须显式键入元组(通过更改类型或显式转换为元组)或完全删除类型。 【参考方案1】:

您无法让 TypeScript 推断出与明确告知的内容直接矛盾的内容 (Readonly&lt;Array&lt;string&gt;&gt;)。那种类型注解赢得了胜利。

正如您所指出的,修复方法是删除类型注释。但你说过你不能那样做。

由于您无法删除类型注释 - 例如,数组是由您无法控制的代码定义的 - 那么您别无选择,只能复制类型中的可能值列表,当原始更改并且您不更新副本时,这会使您面临维护问题。为了缓解这种情况,您可以添加运行时检查来处理原始更改导致它们不再匹配的情况:

const duplicatedArray = ['hello', 'world'] as const;
type SomeType = typeof duplicatedArray[number]; // 'hello' | 'world'
if ( someArray.length !== duplicatedArray.length ||
     someArray.some((e, i) => e !== duplicatedArray[i])) 
    throw new Error(`'someArray' and 'duplicatedArray' no longer match`);

(其中的运行时部分可能在自动化测试中,而不是在主代码中。)

非常可以说是第二或第三的解决方案,但如果你别无选择,至少也可以。

【讨论】:

好的,感谢您的澄清。由于这(实际上)似乎不可能,我正在考虑手动创建联合类型并相应地缩小数据结构的类型定义。即使这使它稍微重复。 是的,这取决于原件的复杂程度。运行时检查在许多情况下都是现实的,但不是全部。在可能的情况下,它对于捕获错误很有用,但如果不是,则必须依靠手动流程...

以上是关于TypeScript中的类型化数组到文字类型的主要内容,如果未能解决你的问题,请参考以下文章

TypeScript:来自字符串联合文字数组类型,不允许数组中存在任何冗余值

在 TypeScript 中使用类型变量访问对象文字不起作用

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

目前是不是有将两个或多个字符串文字类型连接到 TypeScript 中的单个字符串文字类型?

如何检查字符串文字类型是不是包含 TypeScript 中的值?

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