如何在编译时获取TypeScript类的名称作为字符串字面量?
在TypeScript中编译时提取类名作为字符串字面量是否可行?
需求描述
我想定义一个ExtractName类型,在编译时提取类的name属性作为字符串字面量,期望实现以下效果:
class Class {} // 希望通过编译(Class.name === "Class") const thisShouldCompile: ExtractName<Class> = "Class"; // 希望触发编译错误(Class.name !== "Foo") const thisShouldFail: ExtractName<Class> = "Foo";
我尝试过的写法
以下是我试过的三种写法,但都无法正常工作:
type ExtractName1<C extends Function> = C["name"]; type Broken1 = ExtractName1<Class>; // ^^^^^ Type 'Class' does not satisfy the constraint 'Function'. // Type 'Class' is missing the following properties from type 'Function': apply, call, bind, prototype, and 5 more. type ExtractName2<C extends Pick<Function, 'name'>> = C["name"]; type Broken2 = ExtractName2<Class>; // ^^^^^ Type 'Class' does not satisfy the constraint 'Pick<Function, "name">'. // Property 'name' is missing in type 'Class' but required in type 'Pick<Function, "name">'. type ExtractName3<C extends {name: string}> = C["name"]; type Broken3 = ExtractName3<Class>; // ^^^^^ Type 'Class' does not satisfy the constraint '{ name: string; }'. // Property 'name' is missing in type 'Class' but required in type '{ name: string; }'.
问题原因与解决方案
核心问题
你混淆了类的实例类型和类构造函数的类型:
- 直接写
Class时,TypeScript识别的是这个类的实例类型,实例本身并没有name属性,name是类构造函数这个值的属性。 - 只有通过
typeof Class才能获取到类构造函数的类型,这个类型才包含name属性。
正确实现
调整类型定义的使用方式,传入构造函数的类型即可:
type ExtractName<C extends { name: string }> = C["name"]; class Class {} // 正常通过编译 const thisShouldCompile: ExtractName<typeof Class> = "Class"; // 触发编译错误,符合预期 const thisShouldFail: ExtractName<typeof Class> = "Foo";
这里typeof Class的类型会被TypeScript推断为包含name: "Class"的字面量类型,因此ExtractName<typeof Class>的结果就是字符串字面量"Class",完全满足需求。
总结
这个需求是可以实现的,关键在于区分类的实例类型和构造函数类型——类的name属性属于构造函数的类型,而非实例类型,所以需要用typeof 类名来获取正确的类型传入ExtractName。
内容的提问来源于stack exchange,提问作者Nick White
相关产品推荐
相关产品推荐

