如何让TypeScript编译器识别动态生成的getter与setter?
解决方案
方案1:显式声明属性(简单直接,适合属性固定的场景)
直接在类中用declare关键字提前声明所有动态生成的属性类型即可,declare仅做类型标注,不会生成实际JS代码,不影响原有运行逻辑。
class ColorPalette { // 提前声明动态生成的属性 declare foregroundColor: string; declare backgroundColor: string; declare borderColor: string; #colors = [ ["foregroundColor", "#cccccc"], ["backgroundColor", "#333333"], ["borderColor", "#aaaaaa"] ] as const; constructor() { this.#colors.forEach((e, i) => { Object.defineProperty(this, this.#colors[i][0], { enumerable: true, get() { return this.#colors[i][1]; }, set(hex: string) { if (/^#[0-9a-f]{6}$/i.test(hex)) { this.#colors[i][1] = hex; } } }) }); } toString(): string { return Object.values(this).map(c => c.toString().toUpperCase()).join(", "); } } let redPalette = new ColorPalette(); redPalette.foregroundColor = "#ff0000"; // 不再报错,且会校验类型为字符串 console.log(redPalette.foregroundColor); // 类型提示正常
方案2:统一维护属性列表(避免重复定义,适合属性频繁迭代的场景)
如果希望只修改一处属性列表就能同步更新类型,避免后续属性增减时两边修改出现不一致,可以先定义属性key的元组,再通过映射类型批量生成类的属性声明:
// 统一定义所有颜色key,修改只需改这一处 const COLOR_KEYS = ["foregroundColor", "backgroundColor", "borderColor"] as const; type ColorKey = typeof COLOR_KEYS[number]; // 生成属性映射类型 type ColorPaletteProps = { [key in ColorKey]: string; } class ColorPalette implements ColorPaletteProps { // 批量声明所有动态属性 declare [key in ColorKey]: string; #colors: [ColorKey, string][] = [ ["foregroundColor", "#cccccc"], ["backgroundColor", "#333333"], ["borderColor", "#aaaaaa"] ]; constructor() { this.#colors.forEach((e, i) => { Object.defineProperty(this, this.#colors[i][0], { enumerable: true, get() { return this.#colors[i][1]; }, set(hex: string) { if (/^#[0-9a-f]{6}$/i.test(hex)) { this.#colors[i][1] = hex; } } }) }); } toString(): string { return Object.values(this).map(c => c.toString().toUpperCase()).join(", "); } } let redPalette = new ColorPalette(); redPalette.foregroundColor = "#ff0000"; // 类型校验正常 // 拼写错误会直接编译报错,比如redPalette.foregroundColr = "#ff0000" 会提示属性不存在 console.log(redPalette.toString());
原理解释
TypeScript是静态类型检查工具,无法感知运行时通过Object.defineProperty动态挂载的属性,所以需要我们通过类型声明提前告知TS这些属性的存在和类型,既不会影响原有JS运行逻辑,还能获得完整的编译时校验和编辑器类型提示。
内容的提问来源于stack exchange,提问作者a5hk
相关产品推荐
相关产品推荐

