Typescript 缓存构造函数导致;属性'';没有初始值设定项,并且未在构造函数中明确指定。”;
在我的项目中,我时不时地使用构造函数创建类,这些构造函数缓存它们创建的对象,这样,如果多次使用相同的参数调用构造函数,它每次都返回相同的实例,而不是创建与已创建的实例相同的新实例 下面是一个简单的例子:Typescript 缓存构造函数导致;属性'';没有初始值设定项,并且未在构造函数中明确指定。”;,typescript,constructor,Typescript,Constructor,在我的项目中,我时不时地使用构造函数创建类,这些构造函数缓存它们创建的对象,这样,如果多次使用相同的参数调用构造函数,它每次都返回相同的实例,而不是创建与已创建的实例相同的新实例 下面是一个简单的例子: class X { private static __cache: Record<string, X> = Object.create(null); readonly name: string; // The compilation error happens on
class X {
private static __cache: Record<string, X> = Object.create(null);
readonly name: string; // The compilation error happens on this line.
constructor(name: string) {
const cached = X.__cache[name];
if (cached !== undefined) {
return cached;
}
this.name = name;
X.__cache[name] = this;
}
}
X类{
私有静态_缓存:Record=Object.create(null);
只读名称:string;//编译错误发生在此行。
构造函数(名称:string){
const cached=X.uu cache[name];
如果(缓存!==未定义){
返回缓存;
}
this.name=名称;
X.。_缓存[名称]=此;
}
}
这段代码与TypeScript配合得很好,直到我转到2.7并打开了strictPropertyInitialization
。现在我在只读名称:string代码>说
属性“name”没有初始值设定项,并且未在构造函数中明确指定
在我的项目中,我有多个具有上述模式的类,因此我需要想出一个或多个通用解决方案来消除错误
我不想要两种解决方案:
关闭strictPropertyInitialization
。我发现一般来说关闭它太有用了。打开它显示了一些需要更新的定义,以更好地反映我的一些类的工作方式,或者提示了初始化代码的改进
向name
添加一个明确的赋值断言,以便将其声明为readonly name!:弦代码>。感叹号使TypeScript不再检查是否明确指定了name
。这消除了错误,但它也在编译器检查中为我的口味打了一个太大的洞。例如,如果我使用断言,并且曾经意外地在上面的代码中删除赋值this.name=name
,那么TypeScript不会引发错误。我喜欢被提前通知错误
我在上面给出了一个最简单的例子,但在我的应用程序中,我的类包含更多的字段,或者是通过非常昂贵的计算创建的字段,而不仅仅是通过构造函数参数赋值的字段。对于对象的字段计算昂贵的情况,到目前为止,我首选的解决方案是将构造函数
标记为private
(protected
在某些情况下可能会被指示),并将工厂函数声明为类上的静态成员。像这样:
class X2 {
private static __cache: Record<string, X2> = Object.create(null);
readonly name: string;
private constructor(nameSource: string) {
this.name = expensiveComputation(nameSource);
}
// We use this factory function to create new objects instead of
// using `new X2` directly.
static make(name: string): X2 {
const cached = X2.__cache[name];
if (cached !== undefined) {
return cached;
}
return X2.__cache[name] = new X2(name);
}
}
X2类{
私有静态_缓存:Record=Object.create(null);
只读名称:字符串;
私有构造函数(名称源:字符串){
this.name=费用计算(名称源);
}
//我们使用这个工厂函数来创建新对象,而不是
//直接使用'newx2'。
静态生成(名称:字符串):X2{
const cached=X2.uu cache[name];
如果(缓存!==未定义){
返回缓存;
}
返回X2.\uU缓存[名称]=新的X2(名称);
}
}
由于构造函数总是设置其所有字段,因此TypeScript不再有问题。这要求使用类的代码使用工厂函数来创建新对象,而不是直接使用构造函数。对于构造函数只将其参数分配给字段而不执行任何重要计算的情况,我使用的另一种解决方案是翻转构造函数中的逻辑来执行在检查是否已创建实例之前,请指定字段。如果一个实例已经存在,那么字段分配可能是不必要的,但在分析表明这在实际应用程序中是一个真正的问题之前,我不会担心这一点
看起来是这样的:
class X {
private static __cache: Record<string, X> = Object.create(null);
readonly name: string;
constructor(name: string) {
// Set the fields first...
this.name = name;
// And then figure out whether we have an instance to return.
const cached = X.__cache[name];
if (cached !== undefined) {
return cached;
}
X.__cache[name] = this;
}
}
X类{
私有静态_缓存:Record=Object.create(null);
只读名称:字符串;
构造函数(名称:string){
//首先设置字段。。。
this.name=名称;
//然后确定是否有一个实例要返回。
const cached=X.uu cache[name];
如果(缓存!==未定义){
返回缓存;
}
X.。_缓存[名称]=此;
}
}
使用参数属性,它甚至可以简化为:
class X {
private static __cache: Record<string, X> = Object.create(null);
// The parameter on the constructor also defines the property on
// instances of X.
constructor(readonly name: string) {
// And then figure out whether we have an instance to return.
const cached = X.__cache[name];
if (cached !== undefined) {
return cached;
}
X.__cache[name] = this;
}
}
X类{
私有静态_缓存:Record=Object.create(null);
//构造函数上的参数还定义了
//X的实例。
构造函数(只读名称:string){
//然后确定是否有一个实例要返回。
const cached=X.uu cache[name];
如果(缓存!==未定义){
返回缓存;
}
X.。_缓存[名称]=此;
}
}
如果问题发生在我们自己的代码中,我们能做的最好的事情就是通过添加明确的赋值断言修饰符来手动修复它,就像上面解释的那样:在大多数情况下,一堆!放置在正确的位置将足以修复您的项目