typescript 键入父类使用Object.assign的类示例

4uqofj5v  于 2023-02-20  发布在  TypeScript
关注(0)|答案(1)|浏览(134)

我有以下内容:

type UserModel = {
  id: number;
  email: string;
};

export class ActiveRecord<T> {
  constructor(fields: T) {
    Object.assign(this, fields);
  }
}

class User extends ActiveRecord<UserModel> {}

const user = new User({ id: 1, email: "foo" });

这在JS中完全有效,但是我不能在user上的TS中自动完成,因为它只是User类型,而不是User & UserModel
有什么方法可以完全输入user吗?
运动场

eqfvzcg8

eqfvzcg81#

TypeScript要求interface(包括class声明的示例类型)必须具有 statically known keys。这意味着不可能编写类示例的键名本身为泛型的genericclass声明。您可以定义此类构造函数的预期类型,但是没有class语句将产生该类型的构造函数。
从表面上看,这意味着你所要求的是不可能的,但根据你的用例,你可以解决它。一种方法是Assertclass构造函数是所需的类型:

const ActiveRecord = class {
  constructor(t: any) {
    Object.assign(this, t)
  }
} as { new <T extends object>(t: T): T }

现在有了一个ActiveRecord类构造函数,编译器完全按照预期的方式将其视为泛型,甚至可以将其用作超类,只要在执行此操作时使用具有非泛型键的类型 * 示例化 * T

class User extends ActiveRecord<UserModel> {
  
} // okay

const user = new User({ id: 1, email: "foo" });
console.log(user.id.toFixed(1)); // okay, 1.0

关于示例化的警告意味着您不能这样做:

class Bad<T> extends ActiveRecord<T> { } // error!
// Base constructor return type 'T' is not an object type 
// or intersection of object types with statically known members.

T的键在编译时是未知的,所以编译器会抱怨。你可以让你的子类泛型化,只要ActiveRecord的类型参数没有任何未知的键:

class Good<T> extends ActiveRecord<{ b: T }> { } // okay

只要您不需要最终从ActiveRecord派生的 * 泛型 * 类层次结构,那么这可能是一种可接受的方法。

相关问题