How to define a private property when implementing an interface in Typescript?

ReactjsTypescript

Reactjs Problem Overview


I'm using TypeScript in my project and I have come across an issue. I'm defining an interface like this:

interface IModuleMenuItem {
    name: string;
}

I want to create a class that implements from this interface but I want the name to be a private property like this:

class ModuleMenuItem implements IModuleMenuItem {
    private name: string;
}

I'm getting the following error:

> Class ModuleMenuItem incorrectly implements interface IModuleMenuItem. > Property name is private in type ModuleMenuItem but not in type > IModuleMenuItem.

How can I define a property as private or protected when implementing an interface?

Reactjs Solutions


Solution 1 - Reactjs

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";
    }
}

Solution 2 - Reactjs

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         
    }
 }

Solution 3 - Reactjs

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.

Solution 4 - Reactjs

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 = ...
}

Solution 5 - Reactjs

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$;
    }
}

Solution 6 - Reactjs

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())
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGolan KivitiView Question on Stackoverflow
Solution 1 - ReactjsIvan ZlatevView Answer on Stackoverflow
Solution 2 - ReactjsAbdelrahman HossamView Answer on Stackoverflow
Solution 3 - ReactjsSyntaxView Answer on Stackoverflow
Solution 4 - ReactjsMohammad fView Answer on Stackoverflow
Solution 5 - ReactjsCodetoilView Answer on Stackoverflow
Solution 6 - ReactjsAniket ChowdhuryView Answer on Stackoverflow