Typescript基类,带有类型化的create和patch方法

时间:2019-03-19 14:09:24

标签: typescript

我要创建下一个api:

class BaseModel {
  // has 2 generic methods
  static create(props) { //... }

  patch(props) { //... }
}

class Foo extends BaseModel { //... }

// someProps should be typechecked
const foo = Foo.create(someProps)

// patchProps should be typechecked too
foo.patch(patchProps)

我想出了下一个解决方案(可能根本不是最佳选择):

type PropType<T, P extends keyof T> = T[P];

class BaseModel {
  static create<T extends typeof BaseModel & { props: unknown }, P extends PropType<T, 'props'>>(
    this: T,
    props: P
  ): InstanceType<T> {
    const model = new this() as InstanceType<T>;

    model.patch(props);

    return model;
  }

  // @ts-ignore
  // Don't know how to type this part
  patch(props) {
    // some work, might be untyped
  }
}

class Foo extends BaseModel {
  static props: {
    someString?: string;
  };
}

// this works fine
const t = Foo.create({ someString: 'someString' });

// this is not typechecked, should throw error
t.patch({ someInvalidObject: 1 });

我没有在BaseModel中声明props,因此应该要求在子类上进行声明。

如何使patch方法具有强类型? 也许还有其他方法可以使此api正常工作?

Typescript playground link

1 个答案:

答案 0 :(得分:2)

我们可以在基类中添加泛型类型参数,尽管这样做会在继承类时变得困难。

另一个选择是基类,它具有该方法的一个版本,该版本基本上是不可调用的。然后我们添加patch的适当签名作为create的返回

type PropType<T, P extends keyof T> = T[P];

class BaseModel {
  static create<T extends typeof BaseModel & { props: unknown }, P extends PropType<T, 'props'>>(
    this: T,
    props: P
  ) {
    const model = new this() as InstanceType<T> & {
      patch(props: T['props']): void
    };

    model.patch(props);

    return model;
  }

  patch(props: Record<string, never>) {

  }
}

class Foo extends BaseModel {
  static props: {
    someString?: string;
  };
}


const t = Foo.create({ someString: 'someString' });

t.patch({ someInvalidObject: 1 }); //err
t.patch({ someString: "" }) // ok