高阶函数的返回函数参数的缩小类型

时间:2020-09-23 11:17:56

标签: typescript

我认为标题无法真正传达我在这里想要做的事情。但是我们还是要走了。

我有一个函数,它将返回另一个函数。问题是返回哪种类型的函数取决于我在第一个函数中输入的参数。看起来像这样

Function('function2')('what-ever-parameter-of-function2')
Function('function3')('what-ever-parameter-of-function3')

我想做的是,当我点击第一个()时,它将提供'function2''function3'< / strong>,并在此基础上,当我点击第二个()时,它会自动选择已经在第一个()上选择的确切功能的参数。 / p>

我的情况实际上比这要复杂得多,但是概念基本上就是这个。

This is what I'm trying out. 在此示例中,我尝试在第一个()中具有property1或property2,并基于第二个()中的(function1和function2)或(function3和function4)

已注释掉的代码仅是实验,我能够使其在property1或property2上自动完成,但是在第二个()中没有自动完成的约束

您将在操场上看到一些错误,忽略最后一个,我只是懒惰地编写了该函数的实际实现。我有两个问题。

  1. 在前两个错误中,它会显示

键入'Mutations [M] [string] |变异[M] [数字] | 不能将Mutations [M] [symbol]'分配给类型'(... args:any)=> 任何

我只是不明白为什么打字稿将K视为string | number | symbol

  1. 在此代码中
const testO: TestT = {
      commit: function(name) {
        return (K, P) => 'void';
      }
    }

如果将鼠标悬停在 K 上,您会看到它的类型为never。我有点理解,因为“ property1”和“ property2”内部没有通用功能。但这对我来说毫无意义。我想要的只是在commit(name: 'property1' |'property2')函数中,当我键入name参数时,它将name传递到下一个函数中,该函数将确定要返回的设置函数

1 个答案:

答案 0 :(得分:0)

您的解决方案离我们并不遥远。

您可以使用几个辅助提取器来正确排列所有内容,例如

type ExtractParams<T> = T extends (a: infer K) => any ? K : never
type ExtractReturn<T> = T extends (a: any) => infer K ? K :  never

现在,您的CommitTestT类型变为

type Mutations = {
  'property1': {
    f: (param: string) => void;
    g: (param: string) => string;
  },
  'property2': {
    h: (param: number) => void;
    j: (param: number) => string;
  }
}

type Commit<M extends keyof Mutations> =
  <K extends keyof Mutations[M], P extends Mutations[M][K]>(
    key: K,
    payload: ExtractParams<P> 
  ) => ExtractReturn<P>


type TestT = {
  commit: <K extends keyof Mutations>(
    name: K
  ) => Commit<K>
}

一切都很好

const a = test.commit('property1')(
  "f", "hello" // OK
) // void

const b = test.commit('property2')(
  "h", 1 // OK
) // void

const c = test.commit('property2')(
  "j", 1 // OK
) // string

Playground link