必须避免在属性初始化器中使用 async/await,因 javascript/typescript 语法层禁止异步字段初始化,会导致编译失败或运行时错误;正确做法是将异步逻辑移至显式 async init() 方法中,并配合状态守卫与静态工厂方法确保初始化安全。

直接避免在属性初始化器中使用 async/await——因为 JavaScript 和 TypeScript 都不支持异步属性初始化器,写进去会报语法错误或被忽略,根本无法执行。
属性初始化器本质是同步的
类字段(如 data = await fetch(...))在构造函数执行前由引擎按顺序求值,且必须是同步表达式。任何 await 都会导致 Unexpected token 'await' 语法错误。TypeScript 编译阶段也会报错,不会生成有效代码。
这不是“容易忽略的坑”,而是语言层直接禁止的行为。
常见误写及真实后果
以下写法均非法:
-
class A { data = await fetch('/api'); }→ 语法错误,编译失败 -
class B { data = Promise.resolve().then(() => ...); }→ 合法但危险:字段存的是 Promise,不是数据;后续访问this.data得到的是未 resolve 的 Promise,不是预期值 -
class C { data; constructor() { this.data = await fetch(...); }→ 构造函数里不能await,运行时报Cannot use keyword 'await' outside an async function
正确替代方案:分离构造与加载
把异步逻辑从初始化过程移出,交由显式方法控制:
- 构造函数只做同步赋值:
this._state = 'pending'; this.id = id; - 定义
async init()方法封装所有异步加载逻辑 - 子类重写
init()时,先await super.init(),再加自身逻辑 - 使用者必须调用
await instance.init()后才能安全使用业务方法
增强健壮性的配套措施
防止误用、提升可维护性:
- 在关键方法开头加守卫:
if (this._state !== 'ready') throw new Error('Call init() first'); - 用私有标志位
this._isInitialized = false,init()成功后置为true - 提供静态工厂方法:
static async create(...args) { const inst = new this(...args); await inst.init(); return inst; } - 构建工具中保留关键名(如
init),避免混淆破坏调用链











