简体   繁体   English

我可以让 class 实现一个接口而不重新输入所有类型吗?

[英]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将(至少)有nameaddress 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.

相关问题 我有一个包含 200 多个属性的界面。 class 如何在不再次声明所有 200+ 的情况下实现此接口? - I have an interface with 200+ properties. How can a class implement this interface without declaring all 200+ again? 为什么抽象 class 必须实现接口中的所有方法? - Why does abstract class have to implement all methods from interface? 我可以使用服务(Typescript类)和接口来实现常量和枚举吗? - Can I implement constants and enums with a service (Typescript Class) and an Interface? 使用接口键入 class? - Typing a class with an interface? 为什么在Typescript中实现接口时必须重新声明类型 - why I have to re-declare type when implement interface in typescript 打字稿:映射类型:没有方法的类到接口 - Typescript: Mapped Types: Class to Interface without methods Typescript-使用类作为接口,为什么我必须实现私有成员/方法? - Typescript- Using class as interface, why do I have to implement private members/methods? "带有接口的抽象类的类型化方法" - Typing method of a abstract class with an interface 具有多种可能的 object 类型的接口类型数组 - Interface typing array with multiple possible object types 我可以将未知数量的类型作为 class typescript 的“类型参数”吗 - Can I have a unknown number of types as "type parameters" to a class typescript
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM