首页 > 解决方案 > 在字段数上也是多态的泛型元组的类型是什么?

问题描述

所以初始类型只是一个泛型Pair,我希望能够Pair使用其他字段来扩展它:

type Pair<A, B> = [A, B];

const foo = <A, B, R extends Pair<A, B>>(...args: R): R => args;

foo(123, "foo"); // well-typed
foo(123, "foo", true); // type error but should be well-typed
foo(123, "foo", true, "bar"); // type error but should be well-typed

操场

这怎么可能?

标签: javascripttypescripttypestuples

解决方案


TypeScript 中的元组类型具有数字文字类型的固定length属性。(这是在microsoft/TypeScript#17765中实现的)。所以任何都会有长度:Pair<A, B>2

type PairLength = Pair<any, any>['length']; // 2

表单的通用约束R extends Pair<A, B>意味着它R必须是 的子类型Pair<A, B>。具体R必须具有length可分配给 的属性2。因此,您将无法将[number, string, boolean](whose lengthis 3) 或[number, string, boolean, string](whose lengthis 4) 分配给Pair<A, B>.


我建议这样做。您使用开放式元组而不是固定长度的元组,并带有一个最终的剩余元素。例如:

type PairOrLonger<A, B> = [A, B, ...any[]];

该类型PairOrLonger<A, B>是一个长度为 2 或更大的数组,其第一个元素是 type A,其第二个元素是 type B,之后有零个或多个 type 元素any。如果您检查它,该length属性只是number(TypeScript 没有范围类型,因此您不能说“至少2”作为一种类型):

type PairOrLongerLength = PairOrLonger<any, any>['length']; // number

然后我们可以使用它,foo一切正常,因为我们不再有固定长度的约束R

const foo = <A, B, R extends PairOrLonger<A, B>>(...args: R): R => args;

foo(123, "foo");
foo(123, "foo", true);
foo(123, "foo", true, "bar");

请注意,A并且B没有任何目的,foo因为它们没有被推断出来。您可以使用类似的功能做同样的事情

const bar = <R extends [any, any, ...any[]]>(...args: R): R => args;
bar(123, "foo");
bar(123, "foo", true);
bar(123, "foo", true, "bar");

好的,希望有帮助;祝你好运!

Playground 代码链接


推荐阅读