缓存构造函数触发TypeScript strictPropertyInitialization属性未初始化错误
strictPropertyInitialization Oh I feel this pain—you’ve got this cached singleton-style class that worked perfectly in older TypeScript versions, but as soon as you upgrade to 2.7 and flip on strictPropertyInitialization, that readonly name: string line starts throwing that annoying "Property has no initializer and is not definitely assigned in the constructor" error. Let’s break down why this happens and how to fix it cleanly.
First, let’s make sure we’re on the same page with your minimal example—this is probably what your code looks like, right?
class Person { static cache = new Map<string, Person>(); readonly name: string; private constructor(name: string) { this.name = name; } static create(name: string): Person { if (!this.cache.has(name)) { this.cache.set(name, new Person(name)); } return this.cache.get(name)!; } }
The issue here is that TypeScript’s strictPropertyInitialization rule enforces that every class property (including readonly ones) is either initialized when declared or explicitly assigned in the constructor. Even though your constructor does assign name, TypeScript’s static analysis in early 2.7 versions might not fully connect the dots that your private constructor is only ever called via the create method where the parameter is passed correctly.
Here are your best solutions, ordered from most clean to quick-and-dirty:
1. Use Constructor Parameter Properties (Recommended)
This is the most idiomatic TypeScript solution—it simplifies your code and satisfies the strict check automatically. Just add readonly directly to your constructor parameter, and TypeScript will automatically create the class property, mark it as readonly, and assign the value for you:
class Person { static cache = new Map<string, Person>(); // The readonly modifier here does all the work private constructor(readonly name: string) { // No need for manual assignment—TS handles it! } static create(name: string): Person { if (!this.cache.has(name)) { this.cache.set(name, new Person(name)); } return this.cache.get(name)!; } }
This keeps your code clean, maintains the readonly guarantee, and plays perfectly with TypeScript’s strict rules.
2. Add a Non-Null Assertion to the Property
If you want to keep your existing structure, you can tell TypeScript to trust that you’ll initialize the property by adding a ! after the property name. This suppresses the error while keeping your code mostly the same:
class Person { static cache = new Map<string, Person>(); // The ! tells TS "I promise this will be initialized" readonly name!: string; private constructor(name: string) { this.name = name; } static create(name: string): Person { if (!this.cache.has(name)) { this.cache.set(name, new Person(name)); } return this.cache.get(name)!; } }
Note: This is a bit of a "trust me" hack—if you ever modify your constructor and forget to assign name, TypeScript won’t warn you. Use this only if you’re sure you won’t break the initialization logic later.
3. Disable the Check for the Class/Property
If you really can’t adjust your code structure, you can disable the strictPropertyInitialization check for just this class or property using a @ts-ignore comment:
// Disable the check for the entire class // @ts-ignore: strictPropertyInitialization class Person { static cache = new Map<string, Person>(); readonly name: string; private constructor(name: string) { this.name = name; } static create(name: string): Person { if (!this.cache.has(name)) { this.cache.set(name, new Person(name)); } return this.cache.get(name)!; } }
Or target just the property:
class Person { static cache = new Map<string, Person>(); // Disable the check for only this property // @ts-ignore: strictPropertyInitialization readonly name: string; private constructor(name: string) { this.name = name; } static create(name: string): Person { if (!this.cache.has(name)) { this.cache.set(name, new Person(name)); } return this.cache.get(name)!; } }
This is the least recommended option because it weakens TypeScript’s type safety, but it’s an option if you’re stuck in a pinch.
内容的提问来源于stack exchange,提问作者Louis

