TypeScript中如何判断接口键的类型
报错核心原因
你遇到的'Dog' only refers to a type, but is being used as a value here错误,本质是TypeScript的类型擦除机制导致的:interface是纯编译阶段的类型构造,只在TS做静态类型校验时生效,代码编译为JavaScript运行时,所有接口、类型别名这类纯类型代码都会被完全删除,运行环境里根本不存在名为Dog的实体值,自然没法通过typeof Dog['name']这种写法读取属性类型。
你写的普通变量hi之所以能做typeof检查,是因为hi是真实存在的运行时值,编译后不会被删掉。
对应场景的解决方法
根据你要做的是编译期类型获取还是运行时类型检查,选对应方案即可:
场景1:仅需要编译期拿到接口键的类型
如果不需要在代码运行时做判断,只是想在写代码阶段获取接口某个键的类型做类型约束,TS原生就支持索引访问类型语法,完全可以实现:
interface Dog { name: string; } // 编译阶段就能拿到Dog接口name键的类型,等价于type DogNameType = string type DogNameType = Dog['name']; // 做类型校验时,传错类型TS会直接在开发阶段报错 const validName: DogNameType = "Lucky"; // 正常 const invalidName: DogNameType = 123; // 编译飘红:number不能赋值给string类型
场景2:需要在代码运行时做类型检查
如果要在代码执行阶段判断某个值的类型是否匹配接口结构,就不能只靠interface,必须搭配编译后仍然存在的运行时值来实现,常用方案有两种:
- 方案1:定义和接口结构对齐的Schema常量,搭配类型守卫做校验
interface Dog { name: string; } // 这个schema是真实的JS对象,运行时可访问,satisfies语法保证它和Dog接口的键完全对齐 const dogFieldTypeMap = { name: 'string' } satisfies Record<keyof Dog, string>; // 写一个类型守卫函数,运行时校验入参是否符合Dog结构 function isDog(input: unknown): input is Dog { return typeof input === 'object' && input !== null && typeof (input as Record<string, unknown>).name === dogFieldTypeMap.name; } // 使用 const testVal = { name: 'ErHa' }; if (isDog(testVal)) { console.log('yes, it is', testVal.name); // 这里TS会自动推导testVal为Dog类型,不会报类型错误 }
- 方案2:用类代替接口,类同时具备类型和运行时值的属性
TS的类既可以当类型做静态校验,编译后也会生成真实的JS构造函数,能在运行时访问:
class Dog { name!: string; // !表示该属性会被赋值,避免TS初始化校验报错 // 类上挂载静态校验方法 static checkIsDog(input: unknown): input is Dog { return typeof input === 'object' && input !== null && typeof (input as Record<string, unknown>).name === 'string'; } } // 编译期当类型用 const myDog: Dog = { name: 'Corgi' }; // 运行时直接调用类的静态方法做校验 if (Dog.checkIsDog(myDog)) { console.log('校验通过'); }
注意:哪怕用类,也没法直接通过
typeof Dog['name']拿到属性类型——类的属性类型信息同样会在编译时被擦除,运行时类型检查必须手写判断逻辑,或者借助专门做运行时类型校验的库自动生成类型和校验逻辑。
内容的提问来源于stack exchange,提问作者Juan Antonio
相关产品推荐
相关产品推荐

