Mixin中的打字稿覆盖构造函数参数

时间:2020-09-27 00:36:07

标签: javascript typescript oop ecmascript-6

在我当前的打字稿项目中,我试图创建一个mixin,以便创建多个从不同基类继承的子类。

一切正常,但是我似乎无法弄清楚如何告诉打字稿新的派生类具有与基类不同的参数。这是一个示例,说明了我要在这里做什么

interface ConstructorFoo {
  bar: string,
}

class Foo {
  public bar: string
  constructor({ bar }: ConstructorFoo) {
    this.bar = bar
  }
}

interface ConstructorBaz extends ConstructorFoo {
  qux: string
}

type FooType = new (...args: any[]) => Foo
const quxMixin = <T extends FooType>(base: T) => {
  return class Baz extends base {
    public qux: string
    constructor (...args: any[]) {
      super(...args)
      const { qux } = args[0] as ConstructorBaz
      this.qux = qux
    }
  }
}

const FooBaz = quxMixin(Foo)


const q = new FooBaz({
  bar: '1',
  qux: '2'  // Argument of type '{ bar: string; qux: string; }' is not assignable to parameter of type 'ConstructorFoo'.
            // Object literal may only specify known properties, and 'qux' does not exist in type 'ConstructorFoo'.
})

但是我收到以下错误,因为我不知道如何指定class Baz具有不同的参数类型:

Argument of type '{ bar: string; qux: string; }' is not assignable to parameter of type 'ConstructorFoo'.
Object literal may only specify known properties, and 'qux' does not exist in type 'ConstructorFoo'.

感谢您的帮助,这里的a playground link detailing exactly what I want to do

1 个答案:

答案 0 :(得分:1)

尝试一下:

doctorInfo.exec(function(err,data){
    if(!err){
        if(data && data.length && data.length >0){
        data.forEach(foundInfo=>{
            let obj ={
                id: foundInfo._id,
                label: foundInfo.name,
            };
            foundInfo.visits +=1;
            foundInfo.save();
            result2.push(obj.label);
        });
    }
    }
    else{
    console.log(err);
    }
    });

这使用实用程序类型InstanceTypeConstructorParameters

/** A constructor that constructs a T using the arguments A */
type Constructor<T = any, A extends any[] = any[]> = new (...args: A) => T
/** Exclude the first element of an array */
type Tail<T extends any[]> = T extends [any, ...infer U] ? U : never

interface Qux {
  qux: string
}

/** Add the Qux type to the first item in an array */
// If the T is empty, T[0] will be never and T[0] & Qux will also be never, so
// this needs to check if the array is empty
type AddQux<T extends any[]> = T extends [] ? [Qux] : [T[0] & Qux, ...Tail<T>]

// quxMixin accepts a constructor base and returns another constructor
const quxMixin = <T extends Constructor>(base: T): Constructor<
  // that constructs the original class with the qux property
  InstanceType<T> & Qux,
  // using the same arguments as the original constructor except that the first
  // parameter includes the qux property
  AddQux<ConstructorParameters<T>>
> => {
  return class Baz extends base {
    public qux: string
    constructor (...args: any[]) {
      super(...args)
      const { qux } = args[0] as Qux
      this.qux = qux
    }
  }
}

const FooBaz = quxMixin(Foo)

const q = new FooBaz({ bar: '1', qux: '2' })
q.qux // string

Playground link