我要创建下一个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正常工作?
答案 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