如何使用泛型声明工厂方法

时间:2020-03-14 15:09:19

标签: typescript typescript-generics

class Context {

}

class MyClass1 {
    constructor(context: Context, argv: number) {
        //do something with context
    }
}

class MyClass2 {
    constructor(context: Context, argv1: string, argv2: number) {
        // do something with context
    }
}

type ExcludeContext<T extends new (context: Context, ...argv: any) => any> =
    T extends new (context: Context, ...argv: infer P) => any ? P : never

type a = ExcludeContext<typeof MyClass1> // [number]
type b = ExcludeContext<typeof MyClass2> // [string, number]

class Factory {
    constructor(private context: Context) { }

    createObj(template: typeof MyClass1, ...argv: ExcludeContext<typeof MyClass1>) {
        return new template(this.context, ...argv)
    }
    createObj2<T extends (typeof MyClass1) | (typeof MyClass2)>(template: T, ...argv: ExcludeContext<T>) {
        // Oops,compiler prompt error for argv 
        // Expected 3 arguments, but got 1 or more.
        // An argument for 'argv' was not provided
        return new template(this.context, ...argv)
    }
}

我有很多类都将contenxt用于constructor
但是,上下文是为从Factory传递而设计的,因此这些类应由Factory创建。
我想实现一个简单的通用方法来创建objs。 createObj可以,但是当我尝试声明泛型方法createObj2时出错。
template显示为new (context:Context,argv1:never,argv2:number)=>MyClass1|MyClass2

1 个答案:

答案 0 :(得分:2)

仍然具有未解析类型参数的条件类型通常不是TS试图引起重视的东西。通常最好避免在泛型函数的实现中使用条件类型。如果必须使用它们,则可能需要类型断言(return new template(this.context, ...argv as any))。

但是在这种情况下,我们可以使用构造参数和其余参数中的元组重写函数而无需任何条件类型:


class Factory {
  constructor(private context: Context) { }
  createObj<T extends MyClass1 | MyClass2, U extends any[]>(template: new (context: Context, ...args: U) => T, ...argv: U) {
    return new template(this.context, ...argv)
  }
}


let f = new Factory(new Context());
f.createObj(MyClass2, "A", 1)
f.createObj(MyClass1, 1)
f.createObj(MyClass1, "A") // err

Playground Link