给定一个使用此处描述的技术创建的强类型元组:
const tuple = <T extends string[]>(...args: T) => args;
const furniture = tuple('chair', 'table', 'lamp');
// typeof furniture[number] === 'chair' | 'table' | 'lamp'
Run Code Online (Sandbox Code Playgroud)
我想在设计时断言它对另一种联合类型是详尽无遗的:
type Furniture = 'chair' | 'table' | 'lamp' | 'ottoman'
Run Code Online (Sandbox Code Playgroud)
我如何创建一个类型来确保furniture包含联合中的每个类型Furniture?
目标是能够在设计时像这样创建一个数组,如果它失败应该Furniture改变;理想的语法可能如下所示:
const furniture = tuple<Furniture>('chair', 'table', 'lamp')
Run Code Online (Sandbox Code Playgroud)
TypeScript 并没有真正直接支持“穷举数组”。您可以引导编译器进行检查,但这对您来说可能有点麻烦。一个绊脚石是缺少部分类型参数推断(如microsoft/TypeScript#26242 中所要求)。这是我的解决方案:
type Furniture = 'chair' | 'table' | 'lamp' | 'ottoman';
type AtLeastOne<T> = [T, ...T[]];
const exhaustiveStringTuple = <T extends string>() =>
<L extends AtLeastOne<T>>(
...x: L extends any ? (
Exclude<T, L[number]> extends never ?
L :
Exclude<T, L[number]>[]
) : never
) => x;
const missingFurniture = exhaustiveStringTuple<Furniture>()('chair', 'table', 'lamp');
// error, Argument of type '"chair"' is not assignable to parameter of type '"ottoman"'
const extraFurniture = exhaustiveStringTuple<Furniture>()(
'chair', 'table', 'lamp', 'ottoman', 'bidet');
// error, "bidet" is not assignable to a parameter of type 'Furniture'
const furniture = exhaustiveStringTuple<Furniture>()('chair', 'table', 'lamp', 'ottoman');
// okay
Run Code Online (Sandbox Code Playgroud)
如您所见,exhaustiveStringTuple是一个柯里化函数,其唯一目的是采用手动指定的类型参数T,然后返回一个新函数,该函数采用类型T受调用约束但由调用推断的参数。(如果我们有适当的部分类型参数推断,可以消除柯里化。)在您的情况下,T将指定为Furniture. 如果您只关心exhaustiveStringTuple<Furniture>(),那么您可以改用它:
const furnitureTuple =
<L extends AtLeastOne<Furniture>>(
...x: L extends any ? (
Exclude<Furniture, L[number]> extends never ? L : Exclude<Furniture, L[number]>[]
) : never
) => x;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
586 次 |
| 最近记录: |