能否使用Class.name作为变量命名TypeScript接口属性?
问题解答
这种实现方式不可行,原因和正确的实现方法如下:
为什么原代码不符合预期?
TypeScript对接口的计算属性名有严格限制:只有当计算属性名是字符串字面量类型或唯一symbol类型时,才会被解析为具体的接口属性;如果是普通的string类型值(比如MyClass.name的类型是string,而非字面量类型),TypeScript会将其视为索引签名,此时Actions接口等价于:
interface Actions { [key: string]: string | number; }
这意味着变量b的类型检查会非常宽松——你可以添加任意字符串属性,甚至属性值类型只要是string或number就不会报错,和Actions2的严格类型约束(仅允许指定的两个属性)完全不同,所以a和b的表现不可能一致。
正确的实现方式
要让Actions和Actions2等价,你需要将类名转换为字符串字面量类型,再通过模板字面量类型拼接属性名:
方案1:直接定义字面量常量
如果类名固定,直接写死字面量是最稳妥的方式:
const MyClassName = "MyClass" as const; interface Actions { [`${MyClassName}_action1`]: string; [`${MyClassName}_action2`]: number; }
方案2:从类名推导字面量类型
如果需要从MyClass.name动态获取,但确保编译时类型是字面量,可以用const断言:
const MyClassName = MyClass.name as const; interface Actions { [`${typeof MyClassName}_action1`]: string; [`${typeof MyClassName}_action2`]: number; }
此时typeof MyClassName的类型是"MyClass"(字面量类型),模板字面量拼接后会生成具体的属性名,Actions就和Actions2完全一致了。
注意:如果你的代码会经过打包压缩(比如Webpack、Vite的生产模式),MyClass.name在运行时可能被重命名为短字符串(比如a),此时这种动态方式会导致运行时属性名和编译时类型不匹配。如果需要兼顾编译时类型安全和运行时正确性,建议直接使用字面量常量定义类名。
内容的提问来源于stack exchange,提问作者Andre Elrico
相关产品推荐
相关产品推荐

