[英]Can I have a class implement an interface without re-typing out all the types?
Consider as case where we get some raw data from an API or whatnot that we expect to have a shape of ICustomer
, but then we want to extend that functionality, with member functions and perhaps additional variables as part of a Customer
class.考虑这样一种情况,我们从 API 或诸如此类的东西中获取一些我们期望具有
ICustomer
形状的原始数据,但随后我们想要扩展该功能,使用成员函数和可能的附加变量作为Customer
class 的一部分。
interface ICustomer {
name: string;
address: string;
}
class Customer implements ICustomer {
...
}
From this, the compiler knows that Customer
will have (at least) name
and address
.由此,编译器知道
Customer
将(至少)有name
和address
。 Is there a way to have these be defined without my explicitly typing them out?有没有办法在我不明确输入它们的情况下定义它们? Basically what I'd like to do is
基本上我想做的是
class Customer implements ICustomer {
constructor(data: ICustomer) {
Object.assign(this, data)
}
someExtraFunctionality() { ... }
}
It seems silly that I would have to define each member twice.我必须为每个成员定义两次,这似乎很愚蠢。
Is this doable in some clean way?这以某种干净的方式可行吗? I imagine I could do some hackery with
as any as Customer
, but it feels there should be a better way.我想我可以对
as any as Customer
进行一些黑客攻击,但感觉应该有更好的方法。
UPDATED更新
You can try to use type instead of interface您可以尝试使用类型而不是接口
type CustomerType = {
name: string;
address: string;
}
class Customer {
constructor(data: CustomerType) {
Object.assign(this, data)
}
}
OLD ANSWER旧答案
This can work with all optional attributes这可以与所有可选属性一起使用
data = Object.assign(this, data)
I usually assign values this way我通常这样赋值
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() { ... }
}
but again, it only works if all your interface attributes are optional但同样,它仅在所有接口属性都是可选的情况下才有效
interface ICustomer {
name?: string;
address?: string;
}
It's not simple like Object.assign
but it's useful for your case.它不像
Object.assign
那样简单,但对您的情况很有用。
Not really, no.不是真的,不。
You could use the class's instance type as an interface:您可以使用类的实例类型作为接口:
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' })
Here the constructor takes an object that is only the value properties, no methods, and assigns it to the instance.这里构造函数采用一个 object ,它只是值属性,没有方法,并将其分配给实例。 It requires a cumbersome utility type to strip out the functions though.
它需要一个笨重的实用程序类型来剥离功能。
Similarly, you could use Pick
to grab just the properties you want from the class type:同样,您可以使用
Pick
从 class 类型中获取您想要的属性:
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' })
And this may give you this error:这可能会给你这个错误:
Property 'name' has no initializer and is not definitely assigned in the constructor.(2564)
Which you can solve by adding a !
您可以通过添加一个来解决
!
to the property in order to say that it may be undefined
but you should always treat it as a string
.到该属性,以表明它可能
undefined
,但您应该始终将其视为一个string
。 This makes typescript not care that it doesn't ever look to be initialized.这使得 typescript 不关心它看起来从未被初始化。
name!: string
I wouldn't recommend that though, and this feature is fairly type unsafe and allows bugs to leak in.不过我不推荐这样做,而且这个功能在类型上相当不安全,并且允许漏洞泄漏。
But really, I think duplicating the properties is your best bet.但实际上,我认为复制属性是最好的选择。 It may be little verbose, but Typescript will verify you did it correctly, and yell at you if you didn't making this trivial to get right.
它可能有点冗长,但 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' })
It's simple, it's clear, very type safe, and Typescript will light up red if you get the name of type of any of those props wrong.它很简单,很清楚,类型安全,如果你弄错了任何这些道具的类型名称,Typescript 会亮起红色。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.