TypeScript中能否声明无默认值的类实例对象?
为什么会出现这个情况?
在TypeScript中,如果你只声明类的属性但不进行初始化(比如January: string;这种写法),编译后的JavaScript代码里不会把这些属性添加到类的实例上。TypeScript的类型注解只是编译时的类型检查,编译完成后这些类型信息就被剥离了——JS里只有被显式赋值过的属性才会存在于实例对象中,这就是为什么你new Month()后控制台输出Month {},Object.keys也拿不到属性的原因。
解决方案
下面提供几种可行的办法,让你的Month实例包含所有声明的属性:
1. 直接给属性初始化undefined
这是最直接的方式,给每个属性显式赋值undefined,这样编译后的JS会把这些属性添加到实例上:
export class Month { January: string = undefined; February: string = undefined; March: string = undefined; // ... 其他月份属性依次初始化 }
现在new Month()后,实例就会包含所有月份属性(值为undefined),Object.keys(myMonth)就能返回所有属性名了。
2. 在构造函数中初始化属性
如果觉得在属性声明处赋值不够整洁,可以把初始化逻辑放在构造函数里:
export class Month { January: string; February: string; March: string; // ... 其他月份属性 constructor() { this.January = undefined; this.February = undefined; this.March = undefined; // ... 其他月份属性依次赋值 } }
效果和第一种方法完全一致,只是把初始化逻辑集中到了构造函数中。
3. 利用静态属性批量初始化(适合属性较多的场景)
如果月份属性很多,不想重复写初始化代码,可以维护一个静态的属性名数组,在构造函数中循环赋值:
export class Month { January: string; February: string; March: string; // ... 其他月份属性 // 维护所有月份属性的名称数组 private static readonly monthKeys: Array<keyof Month> = [ 'January', 'February', 'March', // ... 补充其他月份 ]; constructor() { Month.monthKeys.forEach(key => { this[key] = undefined; }); } }
这种方式只需要维护monthKeys数组,减少了重复代码,后期修改属性也更方便。
实现你的需求(赋值specialMonths的非空值)
完成类的修改后,你就可以在mapMyPayload方法中遍历属性并赋值了,这里可以用TypeScript的类型工具保证类型安全:
function mapMyPayload(specialMonths: Partial<Month>) { const myMonth = new Month(); Object.keys(myMonth).forEach(key => { const monthKey = key as keyof Month; // 检查specialMonths中对应属性是否非空 if (specialMonths[monthKey] !== undefined) { myMonth[monthKey] = specialMonths[monthKey]; } }); return myMonth; }
这里用Partial<Month>表示specialMonths是Month的部分属性(允许属性缺失或为undefined),用keyof Month做类型断言,避免类型错误。
内容的提问来源于stack exchange,提问作者roger

