Какой тип универсального кортежа c, который также является полиморфным c в количестве полей? - PullRequest
0 голосов
/ 30 апреля 2020

Итак, начальный тип - это просто обобщенный c 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

Playground

Как это возможно?

1 Ответ

2 голосов
/ 30 апреля 2020

Типы кортежей в TypeScript имеют фиксированный атрибут length типа цифра c литерала . (Это было реализовано в microsoft / TypeScript # 17765 ). Таким образом, любая Pair<A, B> будет иметь длину 2:

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

A generi c ограничение формы R extends Pair<A, B> означает, что R должен быть подтипом Pair<A, B>. В частности, R должно иметь свойство length, присваиваемое 2. Таким образом, вы не сможете присвоить [number, string, boolean] (чей length равен 3) или [number, string, boolean, string] (чей length равен 4) для Pair<A, B>.


Я бы предложил это. вместо кортежей фиксированной длины вы используете открытые кортежи с конечным остальным элементом . Например:

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

Тип PairOrLonger<A, B> - это массив длиной 2 или больше, первый элемент которого типа A, второй элемент типа B и с нулем или более элементы типа 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");

Хорошо, надеюсь, это поможет; удачи!

Детская площадка ссылка на код

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...