Альтернативы универсальному типу с параметрами универсального типа в TypeScript

Предположим, у меня есть два типа общих функций, которые различаются только типом возвращаемого значения. Один имеет тип возврата T, другой T[]:

type F1 = <T>(t: T) => T
type F2 = <T>(t: T) => T[]

Мне было интересно, как эти два типа можно объединить в один общий тип. Я предполагал, что этот новый общий тип будет принимать другой общий тип в качестве параметра (например, параметры шаблона шаблона):

// Caution, Fantasy-TypeScript ahead!

// Accepts generic type R as parameter
// to transform return type of generic function
type F<R> = <T>(t: T) => R<T>

// define F1 and F2 in terms of F
type Id<T> = T
type F1 = F<Id>
type F2 = F<Array>

Однако общие универсальные параметры пока не поддерживаются (март 2021 г.). См. Проблема с TypeScript и связанный вопрос SO для получения дополнительной информации.

Что было бы альтернативой в TypeScript?


person raphinesse    schedule 13.03.2021    source источник


Ответы (1)


Простым подходом было бы использование условных типов:

type F<R> = <T>(t: T) => R extends void[] ? T[] : T

type F1 = F<void>   // <T>(t: T) => T
type F2 = F<void[]> // <T>(t: T) => T[]

Более гибкой реализации можно добиться с помощью индексированных типов доступа:

type R<T> = { Id: T, Array: T[] }
type F<K extends keyof R<any>> = <T>(t: T) => R<T>[K]

type F1 = F<'Id'>    // <T>(t: T) => T
type F2 = F<'Array'> // <T>(t: T) => T[]

См. мой ответ на аналогичный вопрос для более сложного примера этой техники.

person raphinesse    schedule 13.03.2021