问题背景
在某些特定场景下,类变量在初始化时是无法明确定义的,必须等到运行过程中才能确定赋值。
import { IStrategy } from "./IStrategy";
export class StrategyContext {
// 使用多态
private strategy: IStrategy;
// 策略可切换
setStrategy(strategy: IStrategy): void {
this.strategy = strategy;
}
// 统一调用入口
doStrategyMethod(): void {
if (this.strategy === undefined) {
throw new Error("使用策略前需设置策略");
}
this.strategy.exec();
}
}
如上述代码所示,IStrategy接口类型的变量strategy,只有在运行过程中通过setStrategy方法进行赋值时才知道赋值的对象是什么。即strategy具体赋值为哪个实现IStrategy接口的类对象在初始化时是不知道的。
编译之后,得到报错信息:
error TS2564: Property 'strategy' has no initializer and is not definitely assigned in the constructor.
Java VS TypeScript
Java具有真正意义上的构造函数的重载,构造方法是可以完全独立的。所以类变量没有必需非必需的概念,使用时注意非空判断即可。
TypeScript不具有真正意义上的构造函数的重载。本质上只有一个构造函数,该构造函数必须具有与所有构造函数重载兼容的签名。为了实现签名兼容的容易性,自然有必需和非必需的类变量说法,也就有了必需的类变量默认是检查是否初始化赋值的。
解决方案
灵活运用 [变量:变量类型],[变量?:变量类型],将变量声明为必需变量或非必需变量。
必需变量要在声明时或者在构造函数中进行初始化。
非必需变量在编译过程中不会检查是否初始化,因而在使用时,需要进行undefined判断。
上述代码改为如下即可:
import { IStrategy } from "./IStrategy";
export class StrategyContext {
// 使用多态(?: 表示变量为可选,后续使用时应判断undefined)
private strategy?: IStrategy;
// 策略可切换
setStrategy(strategy: IStrategy): void {
this.strategy = strategy;
}
// 统一调用入口
doStrategyMethod(): void {
if (this.strategy === undefined) {
throw new Error("使用策略前需设置策略");
}
this.strategy.exec();
}
}