Создайте тип кортежа возвращаемых типов из массива функций, чтобы мы могли привести результат `map` с этим типом кортежа

Отвечая на этот вопрос, мы я могу найти в этой головоломке.

У нас есть эти три функции:

const func1 = (): RegExp => { throw new Error(); } const func2 = (): number => { throw new Error(); } const func3 = (): Date => { throw new Error(); } const funcs = [func1, func2, func3] as const; 

Мы хотим запустить map для этого массива funcs , вызвать каждый func и поддерживать безопасность типов в результирующем массиве возвращаемых значений.

Это работает:

 type Results = [ ReturnType<typeof func1>, ReturnType<typeof func2>, ReturnType<typeof func3>, ]; const results = funcs.map(task => task()) as Results; results[0].test(''); results[1].toExponential(); results[2].toTimeString(); 

Это не удается:

 type MapToReturnType<T> = { [K in keyof T]: T[K] extends () => any ? ReturnType<T[K]> : never; }; // type TaskResultsToo = readonly [RegExp, number, Date] type ResultsToo = MapToReturnType<typeof funcs>; // Conversion of type '(number | RegExp | Date)[]' to type // 'readonly [RegExp, number, Date]' may be a mistake because // neither type sufficiently overlaps with the other. If this // was intentional, convert the expression to 'unknown' first. // Type '(number | RegExp | Date)[]' is missing the following // properties from type 'readonly [RegExp, number, Date]': 0, 1, 2 const resultsToo = funcs.map(task => task()) as ResultsToo; 

Как мы можем изменить MapToReturnType<T> чтобы получить Results которые работают? Я чувствую, что это как-то связано с модификатором readonly .

Всего 1 ответ


Проблема в том, as const создает кортеж только для readonly . Поскольку MapToReturnType гомоморфен, он сохранит модификаторы, поэтому, если вы передадите кортеж только для readonly вы получите кортеж только для readonly .

Так как map создает простой изменяемый массив, машинопись не позволит вам напрямую ввести assert в кортеж только для чтения.

Простое решение для нас - двойное утверждение, as unknown as ResultsToo . Элегантное решение - удалить модификатор readonly при отображении:

const func1 = (): RegExp => { throw new Error(); }
const func2 = (): number => { throw new Error(); }
const func3 = (): Date => { throw new Error(); }

const funcs = [func1, func2, func3] as const;

type MapToReturnType<T> = {
    -readonly [K in keyof T]: T[K] extends () => any ? ReturnType<T[K]> : never;
};

// type TaskResultsToo = readonly [RegExp, number, Date]
type ResultsToo = MapToReturnType<typeof funcs>;

const resultsToo = funcs.map(task => task()) as ResultsToo;

Есть идеи?

10000