typescript - 强制数组在联合类型上是详尽的
问题描述
给定一个使用此处描述的技术创建的强类型元组:
const tuple = <T extends string[]>(...args: T) => args;
const furniture = tuple('chair', 'table', 'lamp');
// typeof furniture[number] === 'chair' | 'table' | 'lamp'
我想在设计时断言它在另一种联合类型上是详尽的:
type Furniture = 'chair' | 'table' | 'lamp' | 'ottoman'
如何创建一个类型来确保furniture
包含并集中的每个类型Furniture
?
目标是能够像这样在设计时创建一个数组,并且让它失败应该Furniture
改变;理想的语法可能如下所示:
const furniture = tuple<Furniture>('chair', 'table', 'lamp')
解决方案
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
如您所见,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;
推荐阅读
- php - 如何使用 .htaccess 页面创建简单的删除 .php 扩展名?
- php - 调用未定义的方法 Maatwebsite\\Excel\\Excel::selectSheetsByIndex()
- excel - Range 的删除方法失败
- bash - 在读取期间删除 bash 中的当前行
- python-3.x - 如何使用一个“for循环”从视图中渲染图像、标题和到模板的链接
- c++ - 使用 .size() 时在 C++ 中声明变量的不同方式的优势?
- python - ValueError:训练 CNN 时对象 __array__ 方法不生成数组
- mysql - 如何用group by计算每行的字符数
- python - 在python中一次重新缩放多个变量
- php - Laravel Auth Guard 自定义尝试总是返回 null