如何在TypeScript中键入构造函数以及构造函数参数?

时间:2018-12-24 12:31:03

标签: typescript

以下是一些设置代码:

// This is from lib.d.ts
type ConstructorParameters<T extends new (...args: any[]) => any> 
      = T extends new (...args: infer P) => any ? P : never

// Represents a type with a constructor function
type Newable<TType> = {
    new(...params: any[]): TType;
};

// A sample class
class Foo {

    constructor(
        options: { bar: string }
    ) {
    }

    public bar() { }
}

这是我想输入的通用类工厂,但目前我失败了:

// Error: 'T' refers only to a type, but is being used as a value here
declare function create<T>(kind: Newable<T>, options?: 
      ConstructorParameters<typeof T>[0]): T;

我想这样使用它:

var x = create(Foo, { bar2: 'ss' }); // This should fail because the constructor option is wrong
x.bar();

我理解错误,但是有人知道如何使它正常工作吗?

2 个答案:

答案 0 :(得分:1)

您的代码中有几个问题,最大的问题是您无法执行typeof T,您将需要type参数来重发该类而不是该类的实例。如果T是类,则可以使用InstanceType获取该类的实例类型。您还可以使用条件类型来提取构造函数的第一个参数。另外,由于您希望构造函数始终具有一个参数,因此,我不会更好地使用通用的new(...params: any[]): TType;创建一个自定义类型来仅使用一个参数type CtorWithOptions<TOpt extends object, T> = new (o: TOpt)=> T来代表构造函数。

将它们放在一起:

// A sample class
class Foo {

    constructor(
        options: { bar: string }
    ) {
    }

    public bar() { }
}

type CtorWithOptions<TOpt extends object, T> = new (o: TOpt)=> T
type OptionsFromConstructor<T> =  T extends CtorWithOptions<infer TOpt, any> ? TOpt : never;
declare function create<T extends CtorWithOptions<any, any>>(kind: T, options: OptionsFromConstructor<T>): InstanceType<T> {
    return new kind(options);

}

var x = create(Foo, { bar2: 'ss' }); // Fails
var x = create(Foo, { bar: 'ss' }); // OK
x.bar();

答案 1 :(得分:0)

替代解决方案,更接近原始代码段:

type Newable<TType extends new(...args:any[]) => InstanceType<TType>> = {
    new(...params: any[]): InstanceType<TType>;
};


// A sample class
class Foo {

    constructor(
        options: { bar: string }
    ) {
    }

    public bar() { }
}

declare function create<T extends Newable<T>>(kind: T, options?: 
 ConstructorParameters<T>[0]): InstanceType<T>;

var x = create(Foo, { bar2: 'ss' }); // Error as expected
x.bar();