如何定义一个私有属性时,实现一个类型的接口?

我在项目中使用 TypeScript,遇到了一个问题。 我定义了这样一个接口:

interface IModuleMenuItem {
name: string;
}

我想创建一个从这个接口实现的类,但我希望这个名称是一个私有属性,如下所示:

class ModuleMenuItem implements IModuleMenuItem {
private name: string;
}

我得到了以下错误:

类 ModuleMenuItem 不正确地实现接口 IModuleMenuItem。 属性名在 ModuleMenuItem 类型中为私有,但在类型中不为私有 IModuleMenuItem.

在实现接口时,如何将属性定义为 private 或 protected?

86667 次浏览

Interfaces define "public" contracts and as such it doesn't make sense to have protected or private access modifier on interfaces, which are more of a, let's call it, implementation detail. For that reason you can't do what you want with an interface.

If you want to make the property read-only to consumers, but overridable in a subclass then you can do something like this:

interface IModuleMenuItem {
getName(): string;
}


class ModuleMenuItem implements IModuleMenuItem {
private name;


public getName() {
return name;
}


protected setName(newName : string) {
name = newName;
}
}

I think in TypeScript 2.0 (not out yet) you will be able to use the readonly access modifier if you were after initialization-time readonly field - https://basarat.gitbooks.io/typescript/content/docs/types/readonly.html

interface IModuleMenuItem {
readonly name : string;
}


class ModuleMenuItem implements IModuleMenuItem {
public readonly name : string;


constructor() {
name = "name";
}
}

I think you may do it like this

interface IModuleMenuItem{
name: string
}


class ModuleMenuItem implements IModuleMenuItem {
private _name: string;
constructor() {
_name = "name";
}


get name(){
// your implementation to expose name
}


set name(value){
// your implementation to set name
}
}

The only way you can have an inner state and assign interface to that instead of class and make that state private

class A{
private state:IA = ...
}

Use abstract classes instead.

Composition over inheritance.

interface AppInterface {
app: express.Application
port: string | number
}


abstract class AbstractApp implements AppInterface {
app: express.Application
port: string | number
constructor(){
this.app=express()
this.port=8080
}
    

protected defaultMiddlewares(): void {}
}


class App extends AbstractApp {
constructor() {
super()
}


protected defaultMiddlewares(): void {
this.app.use(express.json())
}
}

In case of having private fields in class, you need to introduce setter and get methods for that field like so:

export class Model {
private _field: number;


get field(): number {
return this._field;
}


set field(value: number) {
this._field= value;
}
}

And then create the interface as usual (We can not use private modifier for interface fields) like so:

export interface IModel {
field: number;
}

Then implement it to our class like so:

export class Model implements IModel {
...
}

TypeScript will understand that this model is implemented correctly the interface as we have introduced set and get method.

As an addendum to Syntax's response, there is no need to include a setter. A getter method is all that is needed. This could be used, for example, for read-only variables set at initialization, though I suppose it's better to use the readonly modifier in this case.

interface IModuleMenuItem
{
name: string;
}


class ModuleMenuItem implements IModuleMenuItem{
private name$: string;


constructor(name: string)
{
this.name$ = name;
}


public get name()
{
return this.name$;
}
}