难以理解类型索引

Trouble understanding type indexing

我无法理解以下类型定义:

type MergeHandlersReturnType<H extends Record<string, any>> = {
  [K in keyof H]: ReturnType<H[K]>
}[keyof H]

使用相似类型分解上述定义我不明白为什么以下会给我编译器错误

interface R1 extends Record<string, any> {
  "key1": () => 0|1
}

const v1: R1 = {
  "key1": () => 1,
  "key2": () => 2,
  "key3": () => 3
}

type Merged<R1> = {
  [K in keyof R1]: ReturnType<R1[K]>
                              ^^^^^
    }[keyof R1]


Type 'R1[K]' does not satisfy the constraint '(...args: any) => any'.
  Type 'R1[keyof R1]' is not assignable to type '(...args: any) => any'.
    Type 'R1[string] | R1[number] | R1[symbol]' is not assignable to type '(...args: any) => any'.
      Type 'R1[string]' is not assignable to type '(...args: any) => any'.ts(2344)

我原以为 Merged 类型是 R1 键的 return 类型的并集,但索引失败了。

通用参数 R1 必须扩展 Record<string, any> 才能正常工作,或者假设它是任何参数。

或者更准确地说,它需要扩展一个支持indexed signatures的类型。

如果将 Merged<> 的定义与原始定义进行比较,您应该能够看到您缺少约束。

interface R1 extends Record<string, any> {
  "key1": () => 0|1
}

const v1: R1 = {
  "key1": () => 1,
  "key2": () => 2,
  "key3": () => 3
}

interface MyType {
  [k: string]: any
}

type MergedForMyType<R1 extends MyType> = {
  [K in keyof R1]: ReturnType<R1[K]>
} [keyof R1]

type MergedForRecordGeneric<R1 extends MyType | Record<string, any>> = {
  [K in keyof R1]: ReturnType<R1[K]>
} [keyof R1]

您看到编译器错误的原因有几个:

  1. Merged<R1> 表示 R1 是泛型类型变量的名称,而不是 R1 接口,因此 R1Merged 非常类似于泛型 T,它没有类型定义,并且假设没有可以通过 T[K].

    访问的属性
  2. Merged<R1>改成Merged后,因为Recordinterface R1 extends Record<string, any> {中有一个类型any,结果Merged union type will always be any... ReturnType in [K in keyof R1]: ReturnType<R1[K]>Record的第二个参数是什么,因为它比较宽泛,不分析R1 界面中的属性。要解决此问题,我建议您添加特定类型而不是像这样的 anyinterface R1 extends Record<string,() => 0|1|2|3> {。当然,另一种方法是摆脱扩展并用你的类型定义你的键,这样你就不必手动定义联合类型并使用 Merged 就像你想要的那样:

interface R1 {
  "key1": () => 0|1
  "key2": () => 2,
  "key3": () => 3
}

这实际上取决于您的用例,希望上面解释了为什么您会在问题中看到错误。

这里是link到playground