在定义中使用 allof 选项的数组,以告诉 TypeScript 所有选项都必须从该数组中实现,

eqqqjvef  于 6个月前  发布在  TypeScript
关注(0)|答案(3)|浏览(52)

🔍 搜索词

Typescript 定义具有变化的数组类型
typescript 数组是必需的
typescript 带有预定义选项的数组

✅ 可实现性检查清单

  • 这不会对现有的 TypeScript/JavaScript 代码造成破坏性的更改
  • 这不会改变现有 JavaScript 代码的运行时行为
  • 这可以在不根据表达式的类型发出不同的 JS 的情况下实现
  • 这不是运行时特性(例如库功能、JavaScript 输出的非 ECMAScript 语法、JS 的新语法糖等)
  • 这个特性将符合我们设计目标的其他部分:https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals

⭐ 建议

Typescript 应该通过列出必须实现的所有可用选项来扩展

type LanguageLocale = "en-gb" | "de" | "fr" | "nl-nl" | "nb-NO"

[
  { id: 'en-gb', name: 'EN' },
  { id: 'de', name: 'DE' },
  { id: 'fr', name: 'FR' },
  { id: 'nl-nl', name: 'NL' },
] satisfies {id: allof LanguageLocale, name: string}[]

在我的建议中,关键字 allof 将描述这个数组需要实现 LanguageLocale 的所有选项。
allof 只能与 [] 一起使用,或者在定义拆分的情况下应被忽略(例如 LanguageEntry 直接在某个地方使用)

type LanguageLocale = "en-gb" | "de" | "fr" | "nl-nl" | "nb-NO"
type LanguageEntry = {id: allO fLanaugeLocale, name: string}
type LanguageEntries = LanguageEntry[]

它也适用于类型 Array<T>

📃 动机示例

动机是找到代码中缺少但必须的地方
想象一下语言选择器,你添加了一种新语言。
在代码中存在以下内容。
它有以下数据:

type LanguageLocale = "en-gb" | "de" | "fr" | "nl-nl" 
[
  { id: 'en-gb', name: 'EN' },
  { id: 'de', name: 'DE' },
  { id: 'fr', name: 'FR' },
  { id: 'nl-nl', name: 'NL' },
] satisfies {id: LanguageLocale, name: string}[]

在添加 "nb-NO" 之后,

type LanguageLocale = "en-gb" | "de" | "fr" | "nl-nl"|"nb-NO"
[
  { id: 'en-gb', name: 'EN' },
  { id: 'de', name: 'DE' },
  { id: 'fr', name: 'FR' },
  { id: 'nl-nl', name: 'NL' },
] satisfies {id: LanguageLocale, name: string}[]

类型仍然有效,目前没有简单的解决方案使 nb-NO 必须实现

💻 用例

这使得在转译时间将运行时错误转换为 TS 错误变得容易,因为这可以在提交之前发现。
有一个解决方法,但你需要重复自己并有多个定义。所以最后,这只是将错误从代码位置转移到类型定义。

7fyelxc5

7fyelxc51#

Typescript为你提供了足够的基础设施,如果你需要的话,可以自己构建这个:

import { AssertTrue, IsExact } from 'conditional-type-checks';

type LanguageLocale = "en-gb" | "de" | "fr" | "nl-nl" | "nb-NO"

const foo = [
  { id: 'en-gb', name: 'EN' },
  { id: 'de', name: 'DE' },
  { id: 'fr', name: 'FR' },
  { id: 'nl-nl', name: 'NL' },
]  as const;

type ActualLanguageLocale = (typeof foo)[number]["id"];
//   ^?

type _ = AssertTrue<IsExact<LanguageLocale, ActualLanguageLocale>>;

Playground
可能有点啰嗦,但你可以根据需要轻松调整实现。

lf3rwulv

lf3rwulv2#

在之前的讨论中提到了 #53171

7xzttuei

7xzttuei3#

这似乎与 allof 量词的位置有关。{ foo: allof U }[] 描述了 U 与包含数组之间的关系,但从语法上讲,量词直接应用于 U ,这是奇怪的。在嵌套数组的情况下,它也变得模糊不清——它修改了哪一组 [] ?
还有这样一个事实,今天 T[]Array<T> 的同义词,后者存在于用户空间,但这并不适用于任意泛型类型...感觉很奇怪,你能够写出 Array<allof U> 但不能写出 Box<allof U> (因为那没有意义)。

相关问题