问题
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