如何实现class常量?
How to implement class constants?
在 TypeScript 中,const
关键字不能用于声明 class 属性。这样做会导致编译器出现 "A class member cannot have the 'const' keyword."
错误
我发现自己需要在代码中明确指出不应更改 属性。我希望 IDE 或编译器在声明 属性 后尝试为其分配新值时出错。你们是如何做到这一点的?
我目前使用的是只读 属性,但我是 Typescript(和 JavaScript)的新手,想知道是否有更好的方法:
get MY_CONSTANT():number {return 10};
我正在使用打字稿 1.8。建议?
PS: 我现在使用的是 typescript 2.0.3,所以我接受了
常量可以在 class 之外声明并在 class 中使用。否则 get
属性 是一个很好的解决方法
const MY_CONSTANT: string = "wazzup";
export class MyClass {
public myFunction() {
alert(MY_CONSTANT);
}
}
TypeScript 2.0 具有 readonly
modifier:
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
这样做的好处是在构造函数中不可赋值,只能存在于一个地方。
Angular 2 提供了一个非常好的功能,称为不透明常量。
创建一个 class 并使用不透明常量在其中定义所有常量。
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!
]
}
]
注入令牌在逻辑上是在不透明令牌之上设计的,不透明令牌在 Angular 4 中已弃用。
您可以在声明中使用 readonly
修饰符标记属性:
export class MyClass {
public static readonly MY_PUBLIC_CONSTANT = 10;
private static readonly myPrivateConstant = 5;
}
要么将 readOnly 修饰符与需要声明的常量一起使用,要么可以在 class 之外声明一个常量,并仅在需要的 class 中使用 get 运算符专门使用它。
为此,您可以使用 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)。
对我来说 none 较早的答案有效。我确实需要将我的静态 class 转换为枚举。
像这样:
export enum MyConstants {
MyFirstConstant = 'MyFirstConstant',
MySecondConstant = 'MySecondConstant'
}
然后在我的组件中,我按照其他答案中的建议添加新的 属性
export class MyComponent {
public MY_CONTANTS = MyConstans;
constructor() { }
}
然后在我的组件模板中我这样使用它
<div [myDirective]="MY_CONTANTS.MyFirstConstant"> </div>
编辑:抱歉。我的问题与 OP 不同。如果有人和我有同样的问题,我仍然把它留在这里。
所有带有 readonly
的回复仅适用于纯 TS 环境 - 如果它曾经被制作成库那么这实际上并没有阻止任何事情,它只是为 TS 提供警告编译器本身。
静态也不正确 - 这是向 Class 添加方法,而不是 class 的 实例 - 所以你需要解决直接。
有几种方法可以解决这个问题,但纯粹的 TS 方法是使用 getter
- 与您已经完成的完全一样。
另一种方法是将其作为 readonly
放入,然后使用 Object.defineProperty
锁定它 - 这几乎与通过 getter 完成的事情相同,但您可以将其锁定为具有一个值,而不是用于获取它的方法 -
class MyClass {
MY_CONSTANT = 10;
constructor() {
Object.defineProperty(this, "MY_CONSTANT", {value: this.MY_CONSTANT});
}
}
默认设置为 read-only,但请查看 docs 了解更多详情。
如果你想封装常量,不一定是class,也可以是命名空间,这里有不同的选择:
const MY_CONST_1 = "MyText"
这是最优选项,生成如下js:
const MY_CONST_1 = "MyText"
其他选项封装在命名空间中:
namespace Constants {
export const MY_CONST_1: string = 'MyText';
}
这会生成以下 js:
var Constants;
(function (Constants) {
Constants.MY_CONST_1 = 'MyText';
})(Constants || (Constants = {}));
和其他选项 class:
abstract class ConstantsClass {
static readonly MY_CONST_1 = "MyText";
}
这会生成以下 js:
class ConstantsClass {
}
ConstantsClass.MY_CONST_1 = "MyText";
你可以选择最适合你的。
在 TypeScript 中,const
关键字不能用于声明 class 属性。这样做会导致编译器出现 "A class member cannot have the 'const' keyword."
我发现自己需要在代码中明确指出不应更改 属性。我希望 IDE 或编译器在声明 属性 后尝试为其分配新值时出错。你们是如何做到这一点的?
我目前使用的是只读 属性,但我是 Typescript(和 JavaScript)的新手,想知道是否有更好的方法:
get MY_CONSTANT():number {return 10};
我正在使用打字稿 1.8。建议?
PS: 我现在使用的是 typescript 2.0.3,所以我接受了
常量可以在 class 之外声明并在 class 中使用。否则 get
属性 是一个很好的解决方法
const MY_CONSTANT: string = "wazzup";
export class MyClass {
public myFunction() {
alert(MY_CONSTANT);
}
}
TypeScript 2.0 具有 readonly
modifier:
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
这样做的好处是在构造函数中不可赋值,只能存在于一个地方。
Angular 2 提供了一个非常好的功能,称为不透明常量。 创建一个 class 并使用不透明常量在其中定义所有常量。
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!
]
}
]
注入令牌在逻辑上是在不透明令牌之上设计的,不透明令牌在 Angular 4 中已弃用。
您可以在声明中使用 readonly
修饰符标记属性:
export class MyClass {
public static readonly MY_PUBLIC_CONSTANT = 10;
private static readonly myPrivateConstant = 5;
}
要么将 readOnly 修饰符与需要声明的常量一起使用,要么可以在 class 之外声明一个常量,并仅在需要的 class 中使用 get 运算符专门使用它。
为此,您可以使用 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)。
对我来说 none 较早的答案有效。我确实需要将我的静态 class 转换为枚举。 像这样:
export enum MyConstants {
MyFirstConstant = 'MyFirstConstant',
MySecondConstant = 'MySecondConstant'
}
然后在我的组件中,我按照其他答案中的建议添加新的 属性
export class MyComponent {
public MY_CONTANTS = MyConstans;
constructor() { }
}
然后在我的组件模板中我这样使用它
<div [myDirective]="MY_CONTANTS.MyFirstConstant"> </div>
编辑:抱歉。我的问题与 OP 不同。如果有人和我有同样的问题,我仍然把它留在这里。
所有带有 readonly
的回复仅适用于纯 TS 环境 - 如果它曾经被制作成库那么这实际上并没有阻止任何事情,它只是为 TS 提供警告编译器本身。
静态也不正确 - 这是向 Class 添加方法,而不是 class 的 实例 - 所以你需要解决直接。
有几种方法可以解决这个问题,但纯粹的 TS 方法是使用 getter
- 与您已经完成的完全一样。
另一种方法是将其作为 readonly
放入,然后使用 Object.defineProperty
锁定它 - 这几乎与通过 getter 完成的事情相同,但您可以将其锁定为具有一个值,而不是用于获取它的方法 -
class MyClass {
MY_CONSTANT = 10;
constructor() {
Object.defineProperty(this, "MY_CONSTANT", {value: this.MY_CONSTANT});
}
}
默认设置为 read-only,但请查看 docs 了解更多详情。
如果你想封装常量,不一定是class,也可以是命名空间,这里有不同的选择:
const MY_CONST_1 = "MyText"
这是最优选项,生成如下js:
const MY_CONST_1 = "MyText"
其他选项封装在命名空间中:
namespace Constants {
export const MY_CONST_1: string = 'MyText';
}
这会生成以下 js:
var Constants;
(function (Constants) {
Constants.MY_CONST_1 = 'MyText';
})(Constants || (Constants = {}));
和其他选项 class:
abstract class ConstantsClass {
static readonly MY_CONST_1 = "MyText";
}
这会生成以下 js:
class ConstantsClass {
}
ConstantsClass.MY_CONST_1 = "MyText";
你可以选择最适合你的。