typescript 如何声明一个数组的类型,该数组包含从类的方法派生的类型的对象?

ru9i0ody  于 2023-03-13  发布在  TypeScript
关注(0)|答案(1)|浏览(111)

我有一个Contract类,它保存函数的合约:

type MethodType = (...args: any) => any;
    class Contract<T extends MethodType> {

    }

我想有一个类似的班为班。我的尝试实现它:

class ContractForClass<T extends Record<string, any>> {
        methods!: Record<string, Contract<MethodType>;

        forMethod(methodName: string): Contract<MethodType> {
            return this.methods[methodName]
        }
        setContractForMethod(method: string, contract: Contract<MethodType>) {
            this.methods[method] = contract
        }

    }

我的问题是方法合同的类型信息丢失了。在下面的例子中,检索到的合同没有它们的原始类型:

const classContract = new ContractForClass<HttpClient<number>>();
    classContract.setContractForMethod("get", new Contract<HttpClient<number>["get"]>)
    classContract.setContractForMethod("post", new Contract<HttpClient<number>["post"]>)

    const getcontract = classContract.forMethod("get")//want Contract<(url: string) => number >
    const postContract = classContract.forMethod("post")//want Contract<(url:string, payload: number) => void>

Playground链接

2izufjch

2izufjch1#

关键是对函数使用Map类型和泛型类型。
还有一个问题,允许设定合同的其他方法比预期的,但这是一个问题的问题。

type MethodType = (...args: any) => any;

    class Contract<T extends MethodType> {

    }

    type Methods<T> = {
        [Key in keyof T]: T[Key] extends MethodType ? Key : never;
    }[keyof T];

    type ContractsFor<T> = { [K in Methods<T>]: T[K] extends MethodType ? Contract<T[K]> : never }

    class ContractForClass<T extends Record<string, any>> {

        methods!: ContractsFor<T>;

        forMethod<K extends Methods<T>>(methodName: K): Contract<T[K]> {
            return this.methods[methodName]
        }

        setContractForMethod<K extends Methods<T>>(method: K, contract: ContractsFor<T>[K]): void {
            this.methods[method] = contract
        }

    }

    class MyHttpClient<T> {
        a: string = "hello"
        get(url: string): T {
            return null as T
        }

        post(url: string, payload: T) {

        }
    }

    const classContract = new ContractForClass<MyHttpClient<number>>();
    classContract.setContractForMethod("get", new Contract<MyHttpClient<number>["get"]>)
    classContract.setContractForMethod("post", new Contract<MyHttpClient<number>["post"]>)
    classContract.setContractForMethod("post", new Contract<MyHttpClient<number>["get"]>)//should be a type error

    const getcontract = classContract.forMethod("get")//got Contract<(url: string) => number >
    const postContract = classContract.forMethod("post")//got Contract<(url:string, payload: number) => void>

Playground链接

相关问题