Тип для пересечения всех возвращаемых типов со списком функций - PullRequest
0 голосов
/ 18 февраля 2020

Скажем, у меня есть массив функций, таких как:

const foo: Array< () => object > = [
    () => ({ one: 'fish' }),
    () => ({ two: 'fish' }),
    () => ({ red: 'fish' }),
    () => ({ blue: 'fish' })        
]

Можно ли написать тип, который будет пересекать типы возврата всех этих функций?

{
  one: string,
  two: string,
  red: string,
  blue: string,
}

В основном тип для результата, если вы сведете все эти функции в один результат.

1 Ответ

3 голосов
/ 18 февраля 2020

Интересная проблема. Это может быть сделано с использованием комбинации отображенных типов и условных типов; нам нужно:

  • Избавиться от аннотации типа Array<() => object>, чтобы фактическое содержимое массива можно было использовать для создания типа,
  • Получить типы функций из типа массива ,
  • Получите типы возврата этих типов функций,
  • Это дает объединение типа {one: string} | {two: string} | {red: string} | {blue: string}, поэтому нам нужно иметь возможность получать имена свойств (keyof не работает на объединение, подобное этому),
  • Получите тип значения, связанный с данным именем свойства в объединении,
  • И, наконец, создайте результат как отображение этих имен свойств в эти типы значений.

Вот реализация:

const foo = [
    () => ({ one: 'fish' }),
    () => ({ two: 'fish' }),
    () => ({ red: 'fish' }),
    () => ({ blue: 'fish' })
];

type ComponentType<A extends any[]> = A extends (infer U)[] ? U : never

type ReturnsUnion = ReturnType<ComponentType<typeof foo>>
// {one: string} | {two: string} | {red: string} | {blue: string}

type KeyOfUnion<T> = T extends infer U ? keyof U : never
// KeyOfUnion<ReturnsUnion> = 'one' | 'two' | 'red' | 'blue'

type ValueInUnion<T, K extends PropertyKey> = T extends { [k in K]: infer V } ? V : never

type Result = { [K in KeyOfUnion<ReturnsUnion>]: ValueInUnion<ReturnsUnion, K> }
// { one: string, two: string, red: string, blue: string }

Playground Link

...