What are the reasons behind the restriction on using non-public members in TypeScript classes?

Consider the following scenario:

class Trait {
    publicMethod() {
        this.privateMethod();
        // do something more
    }

    private privateMethod() {
        // perform a useful action
    }
}

When attempting to implement it like this:

class MyClass implements Trait {
    publicMethod() {}
}

An error is thrown stating:

MyClass improperly implements interface Trait. Property 'privateMethod' is missing in type 'MyClass'

If implemented like this:

class MyClass implements Trait {
    publicMethod() {}

    private privateMethod() {}
}

The error received is:

MyClass improperly implements interface Trait. Types have separate declarations of a private property 'privateMethod'

Attempting the following approach:

class MyClass implements Trait {
    publicMethod() {}

    public privateMethod() {}
}

An error is triggered:

MyClass improperly implements interface Trait. Property 'privateMethod' is private in type 'Trait' but not in type 'MyClass'

This limitation also applies to protected methods, private, and protected properties. It appears that all members of a class must be public in order to implement it successfully.

Why does TypeScript prohibit implementing a class with non-public members?

EDIT: The issue arises because when using `implements`, classes are treated as interfaces and interfaces cannot contain private members. One solution could be to simply ignore non-public members.

This question emerged from a desire to utilize mixins for code reuse. Although composition is an option, there exists a workaround using mixins and non-public members.

Here is a workaround solution:

function applyMixins(derivedCtor: any, baseCtors: any[]) {
    baseCtors.forEach(baseCtor => {
        Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
            derivedCtor.prototype[name] = baseCtor.prototype[name];
        })
    });
}

interface ITrait {
    publicMethod();
}

class Trait implements ITrait {
    publicMethod() {
        this.privateMethod();
        // do something more
    }

    private privateMethod() {
        // perform a useful action
    }
}

class MyClass implements ITrait {
    publicMethod() {}
}

applyMixins(MyClass, [Trait]);

Answer №1

When using the keyword implements, the Trait class is treated as an interface, but interfaces cannot have private methods.

To understand more about mixins and why private methods are not supported, check out this link: https://github.com/Microsoft/TypeScript/issues/5070

Edit: A major issue with private methods in mixins is the potential conflict when two traits have private methods with the same name. It becomes difficult to ensure that they do not interfere with each other, especially with notation like instance['my' + 'method']().

Referencing the TypeScript documentation on CodePlex:

Instead of using 'extends', we use 'implements' which treats classes as interfaces, utilizing only the types from Disposable and Activatable without the actual implementation. This means we need to provide the implementation in the class itself, contradicting the purpose of using mixins.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is it possible to use a '.JS' file downloaded through Node Package Manager (npm) directly in a web browser?

Generally, I am looking to utilize a specific library without relying on Node CMD. For instance: I aim to create a TypeScript playground without having to execute 'tsc.cmd' from "npm\node_modules", instead, I want to directly call the tsc c ...

How can I verify the validity of a regular expression in Typescript without encountering a syntax error?

I am facing an issue with my code where I load a set of regular expressions from an external source. My goal is to determine if a given string is a valid regex without causing the application to crash due to a syntax error. Despite trying to use try/catch ...

Error: Attempting to add types to an object returned from the .map function in JSX Element

When attempting to include the item type in the object returned from the .map function, I encountered a JSX error. I tried specifying item: JSX.Element as the Item type, but this didn't resolve the issue. Can someone provide clarity on this matter? Th ...

Ensuring type safety at runtime in TypeScript

While delving into the concept of type safety in Typescript, I encountered an interesting scenario involving the following function: function test(x: number){ console.log(typeof x); } When calling this method as test('1'), a compile time er ...

Enhance your workflow with Visual Studio Code by incorporating multiple commands

Embarking on my journey to create my first VSC extension by following this tutorial. Within the "extension.ts" file resides a simple hello world command. My ambition is to introduce another command called git_open_modified_files, however, the tutorial la ...

Different types of subscriptions for forkJoin observable

I am currently making two API requests with typed responses and combining them using the Observable.forkJoin method. My goal is to store each of the results in separate typed variables. var observableOrganization: Observable<Organization> = this.get ...

The factory class is responsible for generating objects without specifying their type

I manage a factory that specializes in facilitating dependency injection. Here's an example of what it looks like: import SomeImportantObject from "./SomeImportantObject" import DataInterface from "./DataInterface" class NoodleFactory { this.depen ...

Customize the template of a third-party component by overriding or extending it

I am facing a situation where I need to customize the template of a third party component that I have imported. However, since this component is part of an npm package, I want to avoid making direct changes to it in order to prevent issues when updating th ...

implementing dynamic visibility with ngIf directive in Angular

header.component.html <nav class="navbar navbar-default"> <div class="container-fluid"> <div class="navbar-header"> <a href="#" class="navbar-brand">Recipe Book</a> </div> <div class="collapse na ...

Issue: Unable to load the file named 'script.ts' while employing chrome.scripting.executeScript

Currently, I am working on developing a chrome extension using Vite with React and Typescript along with CRXJS. This is my initial project in this domain. The issue I am encountering is related to executing a script on the current tab when a button is clic ...

Guide to Setting Up "Remember Me" Login for Users in Angular

I am having trouble setting the 'Remember Me' option on my Login page. I tried using localstorage session but it seems like something is missing in the service file that's causing it not to respond properly. I attempted to follow a guide on ...

What is the best way to incorporate Typescript React Components across various projects?

I'm venturing into developing an npm package that involves several react components implemented with typescript. As a newcomer to react and npm, I apologize if my query seems basic. Despite researching online, there isn't much information on this ...

Angular's error notification system seems to be lacking in providing accurate

I'm experiencing an issue with my angular app where errors are not displayed properly. Instead of showing errors in the component and line number, they always appear in main.js. This is different from how errors are displayed in my other angular appli ...

Troubleshooting Next.js and Tailwind CSS Breakpoints: What's causing the

Having trouble with my custom breakpoints. For instance, I attempted the following: <div className="flex flex-row gap-5 mb-5 md:ml-15 sm:ml-15"> ... </div> The margin is not being applied on small and medium screens. Here are the th ...

What is the best way to showcase a component using FlatList?

Discovering the power of React Native combined with TypeScript and Redux Toolkit Hello! I'm currently facing an issue with rendering a list of messages using FlatList. Everything renders perfectly fine with ScrollView, but now I need to implement inf ...

Prevent click events on disabled tabs in PrimeNG tabMenu

I am encountering an issue with PrimeNG's p-tabMenu when it comes to disabled menu items. For example, suppose I have a tabMenu with 4 sub tabs labeled AAA, BBB, CCC, and DDD. This is how the menuItems are set up in the TypeScript component: //.... ...

Incorporating ng2-bootstrap into an Angular2 project with SystemJS starter template

I am attempting to integrate the ng2-bootstrap modal functionality into a component of my project that is built using the angular2-starter. Below is my systemjs.conf.js configuration: /* * This config is only used during development and build phase onl ...

What is the best way to access dynamic URL parameters in the Next.js 13 app router from a nested server-side component?

This query pertains to the Server-Side components in Next.js 13 app router: I have a good grasp on how the slug parameter is passed to the default function in app/blog/[slug]/page.tsx: export default function Page({ params }: { params: { slug: string } }) ...

Next.js does not recognize Typescript Context

I encountered an unexpected custom error while trying to implement custom error notifications in my form. The custom context I set up for this functionality does not seem to be working as intended, resulting in a thrown error for its non-existence. My deve ...

Retrieve the value of a property within the same interface

Is there a way to access an interface prop value within the same interface declaration in order to dynamically set types? I am attempting something like this: export type MethodNames = "IsFallmanagerUpdateAllowed" | "UpdateStammFallmanager& ...