Advertisement
Advertisement


How to implement class constants in typescript?


Question

In TypeScript, the const keyword cannot be used to declare class properties. Doing so causes the compiler to an error with "A class member cannot have the 'const' keyword."

I find myself in need to clearly indicate in code that a property should not be changed. I want the IDE or compiler to error if I attempt to assign a new value to the property once it has been declared. How do you guys achieve this?

I'm currently using a read-only property, but I'm new to Typescript (and JavaScript) and wonder whether there is a better way:

get MY_CONSTANT():number {return 10};

I'm using typescript 1.8. Suggestions?

PS: I'm now using typescript 2.0.3, so I've accepted David's answer

2018/07/28
1
448
7/28/2018 12:37:15 PM

Accepted Answer

TypeScript 2.0 has the readonly modifier:

class MyClass {
    readonly myReadOnlyProperty = 1;

    myMethod() {
        console.log(this.myReadOnlyProperty);
        this.myReadOnlyProperty = 5; // error, readonly
    }
}

new MyClass().myReadOnlyProperty = 5; // error, readonly

It's not exactly a constant because it allows assignment in the constructor, but that's most likely not a big deal.

Alternative Solution

An alternative is to use the static keyword with readonly:

class MyClass {
    static readonly myReadOnlyProperty = 1;

    constructor() {
        MyClass.myReadOnlyProperty = 5; // error, readonly
    }

    myMethod() {
        console.log(MyClass.myReadOnlyProperty);
        MyClass.myReadOnlyProperty = 5; // error, readonly
    }
}

MyClass.myReadOnlyProperty = 5; // error, readonly

This has the benefit of not being assignable in the constructor and only existing in one place.

2019/04/24
690
4/24/2019 9:11:16 PM

Constants can be declare outside of classes and use within your class. Otherwise the get property is a nice workaround

const MY_CONSTANT: string = "wazzup";

export class MyClass {

    public myFunction() {

        alert(MY_CONSTANT);
    }
}
2016/05/17

You can mark properties with readonly modifier in your declaration:

export class MyClass {
  public static readonly MY_PUBLIC_CONSTANT = 10;
  private static readonly myPrivateConstant = 5;
}

@see TypeScript Deep Dive book - Readonly

2017/07/06

Angular 2 Provides a very nice feature called as Opaque Constants. Create a class & Define all the constants there using opaque constants.

import { OpaqueToken } from "@angular/core";

export let APP_CONFIG = new OpaqueToken("my.config");

export interface MyAppConfig {
    apiEndpoint: string;
}

export const AppConfig: MyAppConfig = {    
    apiEndpoint: "http://localhost:8080/api/"    
};

Inject it in providers in app.module.ts

You will be able to use it across every components.

EDIT for Angular 4 :

For Angular 4 the new concept is Injection Token & Opaque token is Deprecated in Angular 4.

Injection Token Adds functionalities on top of Opaque Tokens, it allows to attach type info on the token via TypeScript generics, plus Injection tokens, removes the need of adding @Inject

Example Code

Angular 2 Using Opaque Tokens

const API_URL = new OpaqueToken('apiUrl'); //no Type Check


providers: [
  {
    provide: DataService,
    useFactory: (http, apiUrl) => {
      // create data service
    },
    deps: [
      Http,
      new Inject(API_URL) //notice the new Inject
    ]
  }
]

Angular 4 Using Injection Tokens

const API_URL = new InjectionToken<string>('apiUrl'); // generic defines return value of injector


providers: [
  {
    provide: DataService,
    useFactory: (http, apiUrl) => {
      // create data service
    },
    deps: [
      Http,
      API_URL // no `new Inject()` needed!
    ]
  }
]

Injection tokens are designed logically on top of Opaque tokens & Opaque tokens are deprecated in Angular 4.

2017/06/20

Either use readOnly modifier with the constant one needs to declare or one might declare a constant outside the class and use it specifically only in the required class using get operator.

2017/08/18

All of the replies with readonly are only suitable when this is a pure TS environment - if it's ever being made into a library then this doesn't actually prevent anything, it just provides warnings for the TS compiler itself.

Static is also not correct - that's adding a method to the Class, not to an instance of the class - so you need to address it directly.

There are several ways to manage this, but the pure TS way is to use a getter - exactly as you have done already.

The alternative way is to put it in as readonly, but then use Object.defineProperty to lock it - this is almost the same thing that is being done via the getter, but you can lock it to have a value, rather than a method to use to get it -

class MyClass {
    MY_CONSTANT = 10;

    constructor() {
        Object.defineProperty(this, "MY_CONSTANT", {value: this.MY_CONSTANT});
    }
}

The defaults make it read-only, but check out the docs for more details.

2020/08/09