打字稿:缩短简单 Class 声明

Typescript: Shortening Simple Class Declaration

我有一个 TS 代码模式,我觉得它非常有用,但它非常不 DRY。有什么解决办法吗?

我喜欢将 TS interfaceclass 声明一起“link”。通过这种方式,我拥有一些具有继承性的简单类型数据结构的优势,并且我可以在运行时使用 instanceof 运算符轻松地进行类型检查(这让我可以避免 type predicates,我发现它不安全).

例如,请参见下面的代码,其中我有一个 class Doctor 扩展了一个基础 class Person

interface PersonInterface {
  id: number
  name: string
  surname: string
}
class Person implements PersonInterface {
  id: number
  name: string
  surname: string

  constructor(arg: PersonInterface) {
    this.id = arg.id
    this.name = arg.name
    this.surname = arg.surname
  }
}

interface DoctorInterface extends PersonInterface {
  degree: string
  salary: number
}
class Doctor extends Person implements DoctorInterface {
  degree: string
  salary: number

  constructor(arg: DoctorInterface) {
    super(arg)
    this.degree = arg.degree
    this.salary = arg.salary
  }
}

const doc = new Doctor({
  id: 111,
  name: 'John',
  surname: 'Johnson',
  degree: 'PHD',
  salary: 100000,
})

console.log(doc instanceof Person) // true
console.log(doc instanceof Doctor) // true

一切正常,类型检查很简单,我的 IntelliSense 很满意。一切都很棒。但是正如您所看到的,我为每个 class 重复了 3 次。一次声明 interface,另一次在 class 中实现它,最后一次应用 constructor.

有没有更简洁的方法?在一个大项目中,这变得很难看。

重要 我的 classes 中不需要方法。它们仅用于呈现数据,而不是行为(事实上我正在使用它们来填充 vuex 存储)

首先,没有神奇的语法可以让它变得更好。

但是值得注意的是,一个class可以作为一个接口:

class Person {
  id: number
  name: string
  surname: string

  constructor(arg: Person) {
    this.id = arg.id
    this.name = arg.name
    this.surname = arg.surname
  }
}

// works
const personData: Person = { id: 123, name: 'Al', surname: 'Bundy' }
const person: Person = new Person(personData)

您可能认为这有点奇怪,但是普通对象和 Person 的实例都具有完全相同的 public 接口,因此它们被认为是兼容的。


IMPORTANT I do not need to have methods in my classes. They are used only to rapresent data, not behaviour (in fact I am using them to populate a vuex store)

那你为什么要使用 classes?那就没必要了。符合该接口的普通对象与实现该接口的 class 的实例或多或少没有区别,因此您只需使用以下代码即可节省大量样板文件:

interface Person {
  id: number
  name: string
  surname: string
}

const person: Person = { id: 123, name: 'Al', surname: 'Bundy' }