我可以让一个类在不重新键入所有类型的情况下实现一个接口吗



考虑这样的情况:我们从API或其他什么地方获得一些原始数据,我们希望具有ICustomer的形状,但我们希望扩展该功能,将成员函数和其他变量作为Customer类的一部分。

interface ICustomer {
name: string;
address: string;
}
class Customer implements ICustomer {
...
}

由此,编译器知道Customer将(至少(具有nameaddress。有没有一种方法可以在不需要我显式键入它们的情况下定义它们?基本上我想做的是

class Customer implements ICustomer {
constructor(data: ICustomer) {
Object.assign(this, data)
}
someExtraFunctionality() { ... }
}

我不得不对每个成员定义两次,这似乎很愚蠢。

这在某种程度上可行吗?我想我可以用as any as Customer做一些技巧,但它觉得应该有更好的方法。

不是,不是。


您可以使用类的实例类型作为接口:

type WithoutFunctions<T> = {
[K in keyof T as T[K] extends (...args: any) => any ? never : K]: T[K]
}
class Customer {
name: string;
address: string;
constructor(data: WithoutFunctions<Customer>) {
Object.assign(this, data)
}
someExtraFunctionality() {}
}
const customer = new Customer({ name: 'a', address: 'b' })

在这里,构造函数接受一个只有值属性而没有方法的对象,并将其分配给实例。不过,它需要一个笨重的实用程序类型来去掉这些功能。


类似地,您可以使用Pick从类类型中获取您想要的属性:

type ICustomer = Pick<Customer, 'name' | 'address'>
class Customer {
name: string;
address: string;
constructor(data: ICustomer) {
Object.assign(this, data)
}
someExtraFunctionality() {}
}
const customer = new Customer({ name: 'a', address: 'b' })

这可能会给你这个错误:

Property 'name' has no initializer and is not definitely assigned in the constructor.(2564)

您可以通过将!添加到属性中来解决这个问题,以便表示它可能是undefined,但您应该始终将其视为string。这使得typescript不在乎它看起来永远不会被初始化。

name!: string

不过,我不建议这样做,而且这个功能相当不安全,允许漏洞泄漏


但实际上,我认为复制属性是你最好的选择。这可能有点冗长,但Typescript会验证你做得正确,如果你没有把这些琐碎的事情做好,就会对你大喊大叫。

type ICustomer = {
name: string;
address: string;
}
class Customer implements ICustomer {
name: string;
address: string;

constructor(data: ICustomer) {
this.name = data.name
this.address = data.address
}
someExtraFunctionality() {}
}
const customer = new Customer({ name: 'a', address: 'b' })

它很简单,很清楚,非常安全,如果你弄错了任何道具的类型名称,Typescript就会亮起红色。

更新

你可以尝试使用类型而不是接口

type CustomerType = {
name: string;
address: string;
}
class Customer {
constructor(data: CustomerType) {
Object.assign(this, data)
}
}

旧答案

这可以与所有可选属性一起工作

data = Object.assign(this, data)

我通常以这种方式分配值

class Customer implements ICustomer {
constructor(data: ICustomer = {}) { //assign an empty object as a default value
for (let key in data) {
this[key] = data[key];
}
}
function someExtraFunctionality() { ... }
}

但同样,只有当所有接口属性都是可选的时,它才有效

interface ICustomer {
name?: string;
address?: string;
}

它不像Object.assign那样简单,但它对您的案例很有用。

最新更新