首页 > 解决方案 > 如何制定强制通用类实例适合给定接口的约束?

问题描述

有这个代码:

interface Class {
    new(...args: any[]): any;
}

class Wrapper<C extends Class> {
    asInterface<InstanceType<C> extends I>(): I { // this is where the constraint should go
        return undefined as any as I; // this is not important
    }
}

interface Plane {
    takeoff(): void;
}

interface Car {
    drive(): void;
}

class F35B {
    takeoff() {
        console.log('doing vertical takeoff');
    }
    shoot() {
        console.log('bang bang');
    }
}

const w = new Wrapper<typeof F35B>();
const plane = w.asInterface<Plane>(); // this should pass
const car = w.asInterface<Car>(); // this should not

如何对 asInterface 方法设置约束,使我成为构造函数 C 的实例的扩展?

当然,表达式InstanceType<C> extends I不符合打字稿,但这是问题的关键思想。

标签: typescript

解决方案


Typescript 执行此操作的方法不是I作为通用参数传递,而是将赋值注释为const plane: Plane = ...,如果不可赋值,则让 Typescript 出错。

我还做了另外两个更改。首先是您的Class接口需要在实例类型上是通用的,否则new不会返回正确的类型。第二个是您Wrapper需要在运行时接受包装的构造函数,它不能只调用new泛型参数C,因为泛型在运行时被删除。

所以我认为最终的结果会是这样的:

interface Class<I> {
    new(...args: any[]): I;
}

class Wrapper<C extends Class<InstanceType<C>>> {
  constructor (private Wrapped: C) {} // <----  `C` is inferred
  create () { return new this.Wrapped() }
}

interface Plane {
    takeoff(): void;
}

interface Car {
    drive(): void;
}

class F35B {
    takeoff() {
        console.log('doing vertical takeoff');
    }
    shoot() {
        console.log('bang bang');
    }
}

const w = new Wrapper(F35B); // <---- Pass constructor at runtime

const plane: Plane = w.create();  // OK

const car: Car = w.create(); // Error
//    ~~~
// Property 'drive' is missing in type 'F35B' but required in type 'Car'

打字稿游乐场


推荐阅读