Why the need to redefine properties when implementing an interface in TypeScript?

余生长醉 提交于 2021-01-28 03:56:34

问题


I'm getting into classes and interfaces. And I got one thing about it that annoys me, this is the first time I work with these kind of things so bear with me here..

Let's say I got this interface:

// IFoo.d.ts
export default interface IFoo {
  foo: string;
  bar: number;
}

When I implement it in a class I do the following:

// FooModel.ts
import IFoo from './IFoo';

export default class FooModel implements IFoo {
  foo: string;
  bar: number;

  constructor({ foo, bar }: IFoo = { foo: 'hello', bar: 1 }) {
    this.foo = foo;
  }
}

Why do I have to implement the same properties all over again?

This is basically the same as copy-paste but with a strict convention. Also, I have to type foo and bar a total of 6 times each to get it properly assigned with default optional values, based on an interface.

Is there a more efficient way to do this too?

Edit; I'm trying to achieve the following:

A class with the properties, from which the properties can be used for typescript's checking, like this: interface

export default interface FooDTO {
  foo: string;
  bar: number;
}

model

export interface IFoo {
  foo: string;
  bar: number;
}

export default class FooModel implements IFoo {
  foo: string;
  bar: number;

  constructor({ foo, bar }: IFoo = { foo: 'hello', bar: 1 }) {
    this.foo = foo;
  }
}

controller

export default class FooController {
   public static async readAll(): Array<FooDTO> {
      // some model stuff which maps query to dto
      return Array<FooDTO>result;
   }
}

回答1:


I think the canonical answer to "why do I have to implement the same properties all over again" is in the (increasingly outdated) TypeScript spec:

Note that because TypeScript has a structural type system, a class doesn't need to explicitly state that it implements an interface—it suffices for the class to simply contain the appropriate set of instance members. The implements clause of a class provides a mechanism to assert and validate that the class contains the appropriate sets of instance members, but otherwise it has no effect on the class type.

I added the emphasis above: the implements clause does not affect the class type at all; it doesn't add members to it or change the types of members. All it does is tell the compiler to emit a warning if the class does not conform to the interface.


You may be interested in the GitHub issue microsoft/TypeScript#22815, which suggests that members of implemented interfaces should be copied down into the implementing classes. (The title of the issue is about abstract classes, but the ensuing discussion is not limited to that.) It looks like the sticking point is what to do about optional members (see this comment by the TS team lead). The issue is an older one, but it's still open with a "needs proposal" tag, so if you care a lot about it you might want to go there, give it a 👍, and maybe even give more details on what the behavior should be in edge cases so that it wouldn't be a breaking change.

Inside that issue is a suggested workaround using interface merging to tell the compiler that the class instance interface inherits properties:

interface FooModel extends IFoo { } // merge into FooModel
class FooModel {
    constructor({ foo, bar }: IFoo = { foo: 'hello', bar: 1 }) {
        this.foo = foo;
        this.bar = bar;
    }
}

This is less redundant but might be more confusing than just redeclaring the properties from the interface.


Anyway, hope that helps; good luck!

Playground link to code




回答2:


Instead of an interface, you could use an abstract class. Same benefits as an interface, but with the possibility of extending it:

export abstract class IFoo {
  foo: string;
  bar: number;
}

export default class FooModel extends IFoo {
  constructor({ foo, bar }: IFoo = { foo: 'hello', bar: 1 }) {
    this.foo = foo;
  }
}



回答3:


If you define an interface with only properties you basically defined a data structure type that you can then use to type objects.

For example you could now do this:

const fooObj: IFoo = { foo: "test", bar: 12 };

In other programming languages (eg. Java) it is illegal to define properties on an interface. An interface "normally" defines a way you can interact with an object (meaning methods you can invoke on it). But TypeScript is an exception to this.



来源:https://stackoverflow.com/questions/62120880/why-the-need-to-redefine-properties-when-implementing-an-interface-in-typescript

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!