Перенос переменных типов кортежей в Typescript

#typescript

#машинописный текст #typescript

Вопрос:

Я хочу преобразовать тип кортежа [T1, T1] в какой-то другой [T2, T2] , где T2 это подтип T1 . Пока это моя лучшая попытка, но я не смог определить возвращаемый тип на variadicMapping . Я предполагаю, что решение включает в себя недавно введенные вариационные типы кортежей.

 type T1 = { property: string };
type T2 = T1 amp; { otherProperty: number };

const transformType = <T extends T1>(obj: T): T2 => ({
  ...obj,
  otherProperty: 0,
});

const variadicMapping = <T extends T1[]>(objects: T) => {
  return objects.map((e) => transformType(e));
};

const foo = [{property: 'propertyA' }, { property: 'propertyB' }] as [T1, T1];
const bar = variadicMapping(foo); // T2[] instead of [T2, T2]
  

Ответ №1:

Для этого вам не нужны переменные типы кортежей. Проблема в том, что определение стандартной библиотеки TypeScript для Array.prototype.map() не пытается представить тот факт, что длина массива сохраняется. Существует открытая проблема, Microsoft / TypeScript # 29841, с просьбой решить эту проблему.

Если вам нужно, чтобы компилятор обращал внимание на длину, вам нужно будет использовать свой собственный набор текста для map() , скажем, слияния объявлений. Возможно, что-то вроде этого:

 interface Array<T> {
    map<U>(
        callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any
    ): { [K in keyof this]: U };
}
  

Я использую отображенные типы кортежей для представления сохранения длины, и, в частности, полиморфный this , чтобы отразить тот факт, что мы хотим перебирать ключи любого подтипа Array<T> , который мы, оказывается, используем, например, кортеж.

Но вмешательство в определения таких часто используемых методов может привести к неожиданным результатам в других частях вашей базы кода, поэтому, если вы не хотите беспокоиться о том, должно ли каждое использование map() вести себя таким образом, вы можете использовать утверждение типа, чтобы сообщить компилятору, что результат этого конкретного вызова map() имеет определенную длину и тип:

 const variadicMapping = <T extends T1[]>(objects: T) => {
    return objects.map((e) => transformType(e)) as { [K in keyof T]: T2 };
};
  

В любом случае вы должны получить желаемое поведение:

 const bar = variadicMapping(foo); // [T2, T2]
  

Игровая площадка ссылка на код