所有返回类型与函数列表的交集类型

NSj*_*nas 1 typescript mapped-types

假设我有一个像这样的函数数组:

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

是否可以编写一个与所有这些函数的返回类型相交的类型?

{
  one: string,
  two: string,
  red: string,
  blue: string,
}
Run Code Online (Sandbox Code Playgroud)

基本上,如果将所有这些函数简化为单个结果,将会产生什么结果的类型。

kay*_*ya3 5

有趣的问题。这可以使用映射类型和条件类型的组合来完成;我们需要:

  • 摆脱类型注释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 }
Run Code Online (Sandbox Code Playgroud)

游乐场链接