如何在打字稿中实现类常量?


429

在TypeScript中,const关键字不能用于声明类属性。这样做会导致编译器出现“ A类成员不能具有'const'关键字”的错误。

我发现自己需要在代码中明确指出不应更改属性。如果在声明属性后尝试为该属性分配新值,我希望IDE或编译器出错。你们如何实现这一目标?

我当前使用的是只读属性,但是我是Typescript(和JavaScript)的新手,想知道是否有更好的方法:

get MY_CONSTANT():number {return 10};

我正在使用打字稿1.8。有什么建议吗?

PS:我现在正在使用打字稿2.0.3,所以我已经接受了大卫的回答

Answers:


651

TypeScript 2.0具有readonly修饰符

class MyClass {
    readonly myReadOnlyProperty = 1;

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

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

它不是一个常数,因为它允许在构造函数中赋值,但这很可能没什么大不了的。

替代解决方案

一种替代方法是将static关键字与结合使用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

这样的好处是不能在构造函数中分配,而只能存在于一个位置。


31
要访问外部类的属性,你需要添加export之前的关键字class以及public static在之前readonly的关键字。看到这里:stackoverflow.com/a/22993349
cbros2008 '16

题。不知道为什么需要类名才能在类本身内部使用readOnly属性?'MyClass.myReadonlyProperty'
Saiyaff法鲁克

@SaiyaffFarouk如果我理解您的问题,答案是静态属性作为类的一部分而不是在类的实例上存在。因此,您使用类名而不是包含类实例的变量来访问它们。
JeffryHouser

1
export(外部模块)和public关键词无关的这个问题/答案,但在显性的话题,我个人觉得非常容易看出一个成员当关键字不存在是公开的。我不会因为这个原因而烦恼它,因为它增加了更多的噪音并且不需要键入。这也使公众成员与标记为private或的成员更加不同protected。无论如何,仅是我的意见:)
David Sherret '17

匿名类呢?关于使用static readonly myReadOnlyPropertyclass声明时如何访问的任何想法export default class { ... }?试过this.myVar,self.myVar,静态,默认值...不起作用...(编辑:default.myVar似乎是解决方案,但我遇到类型错误)
Alcalyn

67

常量可以在类外部声明,也可以在类中使用。否则,该get属性是一个不错的解决方法

const MY_CONSTANT: string = "wazzup";

export class MyClass {

    public myFunction() {

        alert(MY_CONSTANT);
    }
}

6
谢谢; 我担心这种实现,因为它不是可移植的(在模型中,常量实际上不是类的一部分),并且会将信息泄漏到更大的范围内,但是它具有成为真正常量的优点,因此我不会无法更改它而不会发出警报声。
BeetleJuice

1
我了解您的担忧,并且发现get在您的情况下非常适合使用属性
j3ff '16

3
根据angular.io/docs/ts/latest/guide/style-guide.html,请使用驼峰大写代替大写。不建议使用大写常量。
Vadim Kirilchuk'3

12
Angular样式指南,而不是TypeScript样式指南。。问题专门针对TypeScript
VeldMuijz

4
@Esko我相信在打字稿中const限于该文件,因为每个文件都是一个模块。要使其可以在外部访问,您需要使用进行声明export const,然后从另一个文件导入。虽然很容易测试。只需const在一个文件中声明一个文件,然后尝试在不进行导出/导入的情况下在另一个文件中使用它,或者在浏览器控制台中使用它即可。
BeetleJuice

42

您可以readonly在声明中使用修饰符标记属性:

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

@see TypeScript Deep Dive书-只读


11

Angular 2提供了一个非常漂亮的功能,称为不透明常量。创建一个类并使用不透明常量定义那里的所有常量。

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

将其注入app.module.ts中的提供程序中

您将可以在每个组件中使用它。

编辑Angular 4:

对于Angular 4,新概念是“注入令牌”和“不透明令牌”在Angular 4中已弃用。

注入令牌在不透明令牌的基础上添加功能,它允许通过TypeScript泛型以及注入令牌在令牌上附加类型信息,从而无需添加@Inject

范例程式码

Angular 2使用不透明令牌

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使用注入令牌

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

注入令牌在逻辑上是在Opaque令牌之上设计的,而Angular 4中已弃用了Opaque令牌。


6
加一。Angular和一个13岁的少年一样稳定。他们在发布功能几个月后就弃用了功能。小气。
Stavm '17

1
减一 这个问题与Angular无关。它正在请求TypeScript解决方案。
Ben Nieting '17

4

要么使用带有常量的readOnly修饰符,要么需要声明一个常量,或者可以在类外部声明一个常量,并仅使用get运算符仅在所需的类中使用它。


1

为此,您可以使用readonly修饰符。这是对象属性readonly只能在对象初始化时被分配。

课程范例:

class Circle {
  readonly radius: number;

  constructor(radius: number) {
    this.radius = radius;
  }

  get area() {
    return Math.PI * this.radius * 2;
  }
}

const circle = new Circle(12);
circle.radius = 12; // Cannot assign to 'radius' because it is a read-only property.

对象文字中的示例:

type Rectangle = {
  readonly height: number;
  readonly width: number;
};

const square: Rectangle = { height: 1, width: 2 };
square.height = 5 // Cannot assign to 'height' because it is a read-only property

值得一提的是,readonly修饰符纯粹是一个打字稿构造,并且当TS编译为JS时,该构造将不会出现在已编译的JS中。当我们修改只读属性时,TS编译器会警告我们(它是有效的JS)。


-2

对我而言,先前的答案均无效。我确实需要将我的静态类转换为枚举。像这样:

export enum MyConstants {
  MyFirstConstant = 'MyFirstConstant',
  MySecondConstant = 'MySecondConstant'
}

然后在我的组件中,按照其他答案的建议添加新属性

export class MyComponent {
public MY_CONTANTS = MyConstans;
constructor() { }
}

然后在我组件的模板中以这种方式使用它

<div [myDirective]="MY_CONTANTS.MyFirstConstant"> </div>

编辑:对不起。我的问题不同于OP的问题。如果还有其他问题,我仍然将其留在这里。


在任何语言中,使用枚举来保存常量都不是一个好习惯。
Sangimed

这是当前可用解决方案的最佳解决方案。我知道这是不应该使用枚举的方式,但是对于Angular来说,这是具有可绑定常量的最简洁的方法。
Janne Harju
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.