繁体   English   中英

如何将接口定义为 class 属性?

[英]How to define an interface as a class property?

当从 class 继承时,您必须使用 super 属性将所需的 arguments 传递给父 class 的构造函数方法,因此,您必须记住哪些是必填字段,因此您必须记住以下示例:

class Person {
  constructor(name: string, age: number) {
    // ...
  }
}

class Boy extends Person {
  constructor(name: string, age: number) { //see, I have to remember property & type
    super(name, age);
  }
}

所以,我在想一种方法,其中一个解决方案是从使用位置 arguments更改为命名 arguments ,因此您可以使用构建器模式来实现这一点,然后您将使用接口,然后您将在childparent之间共享该接口,因此:

interface PersonProps {
  name: string;
  age: number;
}

class Person {
  constructor(props: PersonProps) {
    // props.name ...... props.age
  }
}

class Boy extends Person {
  constructor(personSuper: PersonProps) {
    super(personSuper);
  }
}

现在这种方法的问题是我们打破了内聚规则,这意味着所有相关的代码都应该在一个独立的单元中 go

So, to write a better code, -of course- you'll split these files into multiple files, so the Person class should go to a separate file, and the Boy class should go to a separate file, but the problem is that each这两个文件中的一个取决于PersonProps 接口,在我看来,为该接口创建一个单独的文件不是一个好主意,因为 Person class 和该接口高度相关,所以我要做的是让PersonProps 接口Person class 一起存在于一个文件中。

所以现在是文件树:

.
├── Boy.js
├── Boy.ts
├── Person.js
├── Person.ts
└── tsconfig.json

现在, Person class完成了,现在问题出在Boy class 上,因为它还依赖于PersonProps 接口

所以你可能会想我会从Person.ts 模块中导出PersonProps 接口,其实我不会,主要是因为你可能在一个文件中有多个class,例如Person.ts 文件可能稍后包含多个 class,并且并非所有这些类都会有接口,因此,我们将打破这种模式,慢慢地代码会变成垃圾,因此,我正在寻找的是将该接口包含在Person class,那么该 Person class 的所有实例都将继承实例内的 PersonProps 接口。

说了很多,下面是两个文件现在的样子:

人.ts:

interface PersonProps {
  name: string;
  age: number;
}

class Person {
  constructor(props: PersonProps) {
    // props.name ...... props.age
  }
}

男孩.ts:

import { Person } from "./Person";

class Boy extends Person {
  constructor(personSuper: PersonProps) {
    super(personSuper);
  }
}

现在我们需要将 Boy.ts 与PersonProps接口连接起来,其中一个人会说“嘿,就在前面 go 并从 Person.ts 导出接口,导出接口 PersonProps ...”该解决方案可能有效,但是,,正如我所提到的,这将打破这种模式。 并且代码会慢慢开始发出很大的噪音。

在这里,我们将得出 2 个很好的解决方案:

[第一的]:

在 Person.ts 中,从 Person class 旁边删除 export 关键字,然后在文件末尾写下:

export = {
  Person: {
    Person,
    PersonProps, // ERROR!
  },
};

由于一个非常未知的逻辑原因,这给出了编译时错误,为什么不允许这样做?

[第二]:

正如我之前提到的,只需让PersonProps成为 class 实例中的属性,因此:

所以完整的文件将如下所示:

人.ts:

interface PersonProps {
  name: string;
  age: number;
}

class Person {
  PersonProps: interface; // ERROR!
  constructor(props: PersonProps) {
    // props.name ...... props.age
    this.PersonProps = PersonProps; // ERROR!
  }
}

这里有两个编译时错误:

  1. 接口不是类型。
  2. 您不能将接口设置为 class 中的属性。

现在,最后,在写了这个很长的问题之后:

  • 您对如何完成此解决方案有任何想法吗?
  • 你有更好的主意吗?

你的问题很常见:

类只能将值作为属性,而不是类型。 别担心,有一种方法,TypeScript 中的命名空间也可以有类型,并且可以与任何值(类,function. 或变量)具有相同的名称:代码如下所示:

class Person {
    constructor(props: Person.Props) {
        // ...
    }
}

namespace Person {
    export interface Props {
        name: string;
        age: number;
    }
}

但请记住,这不是 class 属性,因此您不能使用this.Propsthis['Props']

第二

如果您使用普通的 TypeScript 编译器,请使用ECMAScript模块。 TypeScript 自动编译为 Node.js 模块。 您在导入中使用了它,但在导出中没有使用它。 不要使用export = {} 有关更多信息,请参阅TypeScript 文档

在 tsconfig.json 中:

{
    "compilerOptions": {
        // ...
        "moduleResolution": "node",
        "module": "commonjs"
    }
}

接着:

人物.ts

export class Person {
    constructor(props: Person.Props) {
        //...
    }
}

export namespace Person {
    export interface Props {
        name: string;
        age: number;
    }
}

男孩.ts

import {Person} from "./Person";

export class Boy extends Person {
    constructor(props: Person.Props) {
        super(props);
    }
}

笔记:

如果您不知道为什么export在命名空间中,那么没有export的命名空间中的属性是私有的(您只能在命名空间TypeScript 文档中访问它以获取更多信息。另外,将属性props命名为不一样界面。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM