typescript 基于上一个参数更改函数参数类型

jc3wubiy  于 2023-03-04  发布在  TypeScript
关注(0)|答案(2)|浏览(148)

我有一个名为"onHook"的静态函数。这个函数有两个参数,一个ID和一个Callback。我的目标是根据Hook ID的类型更改回调参数的类型。
现在我设法让这个工作:
打字操场

enum HookID {
    OnOpened,
    OnClosed,
}

type HookArguments<T> = 
    T extends HookID.OnOpened ? {
        arg1: string,
        arg2: string
    }:
    T extends HookID.OnClosed ? {
        arg3: boolean,
        arg4: boolean
    } : never;

function onHook<T>(id: HookID, callback: (arg: HookArguments<T>)=> void){
   // **** //
}

onHook<HookID.OnClosed>(HookID.OnClosed, (args)=>{
    /** args.arg3  and  args.arg4 are availables */  
})

但是必须同时在泛型类型和ID参数中声明枚举似乎不是最优的。有没有办法获取ID参数的类型并将其注入Argument泛型类型?
大概是这样的

function onHook(id: HookID, callback: (arg: HookArguments<this.id>)=> void){
   // **** //
}

onHook(HookID.OnClosed, (args)=>{
     // **** //
})
ds97pgxw

ds97pgxw1#

你的意图是id参数和你用来确定callback参数的generic类型是一样的,对吗?

function onHook<T extends HookID>(
    id: T, callback: (arg: HookArguments<T>) => void
) {
    // **** //
}

当你调用它的时候,编译器现在可以从id参数中 * 推断 * T,所以args会自动得到你想要的类型:

onHook(HookID.OnClosed, (args) => {
    /* (parameter) args: {
    arg3: boolean;
    arg4: boolean;
     } */
})

这就是问题的答案,但是顺便说一句,您不需要使用conditional types来定义HookArguments,因为您希望将数字枚举Map到任意类型,所以可以使用对象类型来捕获它,因为对象类型擅长描述从类似于键的类型的Map(stringnumbersymbol,枚举是字符串/数字)转换为其他类型,然后只需使用枚举对对象类型执行index into操作即可查找相关属性:

interface HookArguments {
    [HookID.OnOpened]: { arg1: string, arg2: string },
    [HookID.OnClosed]: { arg3: boolean, arg4: boolean }
}

function onHook<K extends HookID>(
  id: K, callback: (arg: HookArguments[K]) => void
) {
    // **** //
}

onHook(HookID.OnClosed, (args) => {
    /* (parameter) args: {
    arg3: boolean;
    arg4: boolean;
     } */
})

这对于您的目的来说是相同的,但是是一个更传统的实现。
Playground代码链接

von4xj4u

von4xj4u2#

使用onHook<T extends HookID>()而不是<T>的泛型,然后将第一个参数设置为类型T,这仍然需要它是HookID。

function onHook<T extends HookID>(id: T, callback: (arg: HookArguments<T>)=> void){
   // **** //
}

相关问题