映射类方法

时间:2019-08-27 12:28:25

标签: typescript

我有一个带有很多方法的类。

class Users {
  member1(req: M1Request): Promise<M2Response>;
  member2(req: M2Request): Promise<M2Response>;
  member3(req: M3Request): Promise<M3Response>;
}

class OtherClassToWrap { ... }

我用不同的签名包装它的方法,以添加一个额外的arg:

let rawUsers = ... as Users;
let wrappedUsers = wrap(users);

wrappedUsers.member1(... as M1Request, extraArg).then((res: M1Response) => { ... })

我需要正确键入wrap函数来定义结果对象成员的类型。

const wrap = <T>(toWrap: T): ? => {
    let result = {} as T;
    for (const k in t) {
        result[k] = (req, extraArg) => toWrap[k](req);
    }
    return result;
}

我尝试使用[P in keyof T],但是我对如何在特定情况下应用它感到困惑。

1 个答案:

答案 0 :(得分:0)

如果函数始终只有一个参数,则可以使用条件类型提取参数并在末尾添加额外的参数:

type MapFunction<T, TExtra> = {
     [P in keyof T]: T[P] extends (req: infer P) => infer R ? ((req: P, extra: TExtra) => R): T[P]
}
const wrap = <T extends Record<keyof T, (req: any) => Promise<any>>>(toWrap: T): MapFunction<T, string> => {
    let result = {} as MapFunction<T, string>;
    for (const k in toWrap) {
        result[k] = ((req: any, extraArg: any) => toWrap[k](req)) as any;
    }
    return result;
}


let rawUsers = null! as Users;
let wrappedUsers = wrap(rawUsers);
wrappedUsers.member1(null! as M1Request, "").then(o => {}) // o is M2Response

Play

如果您的函数具有多个参数,那么我们将不容易在末尾添加额外的参数。我们可以在一开始使用扩展参数中的元组添加它们:

declare class Users {
  member1(req: M1Request): Promise<M2Response>;
  member2(req: M2Request): Promise<M2Response>;
  member3(req: M3Request, other: string): Promise<M3Response>;
}

type MapFunction<T, TExtra> = {
     [P in keyof T]: T[P] extends (...a: infer A) => infer R ? ((extra: TExtra, ...a: A) => R): T[P]
}
const wrap = <T extends Record<keyof T, (...a: any) => any>>(toWrap: T): MapFunction<T, string> => {
    let result = {} as MapFunction<T, string>;
    for (const k in toWrap) {
        result[k] = ((req: any, extraArg: any) => toWrap[k](req)) as any;
    }
    return result;
}


let rawUsers = null! as Users;
let wrappedUsers = wrap(rawUsers);
wrappedUsers.member1("", null! as M1Request).then(o => {}) // o is M2Response
wrappedUsers.member3("", null! as M3Request, "").then(o => {}) // o is M3Response

play