TypeGuard编写问题:检查对象属性及值时编译报错求优化方案
TypeScript类型守卫的简洁实现方案
问题背景
我尝试编写一个类型守卫,先检查对象是否包含指定属性,再验证该属性值是否符合要求。最初写的代码如下:
const isJson = (myObject: unknown): myObject is Json => { return Boolean( myObject && typeof myObject === 'object' && 'type' in myObject && myObject.type === 'something' ); };
编译项目时触发错误:Property 'type' does not exist on type 'object',只有编译阶段会报错,其他场景TypeScript没有异议。
目前的解决方案是拆分检查逻辑,但不够简洁:
const isJson = (myObject: unknown): myObject is Json => { const hasType = (myObject: unknown): myObject is { [key: string]: unknown; type: unknown } => { return Boolean(myObject && typeof myObject === 'object' && 'type' in myObject); }; if (!hasType(myObject)) { return false; } return Boolean(myObject.type === 'something'); };
我的tsconfig配置如下:
{ "compilerOptions": { "jsx": "react-jsx", "jsxImportSource": "@emotion/react", "allowJs": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, "forceConsistentCasingInFileNames": true, "strict": true, "noImplicitOverride": true, "noPropertyAccessFromIndexSignature": true, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true } }
寻求更优更简洁的实现方式。
简洁实现方案
方案1:链式检查+局部类型断言
通过类型断言临时将对象转为包含type属性的类型,不需要拆分函数,保持代码紧凑:
const isJson = (myObject: unknown): myObject is Json => { return Boolean( myObject && typeof myObject === 'object' && 'type' in (myObject as Record<string, unknown>) && (myObject as { type?: unknown }).type === 'something' ); };
方案2:控制流拆分+窄化(推荐)
先做基础的对象非空检查,再用类型断言缩小范围,逻辑清晰且代码简洁:
const isJson = (myObject: unknown): myObject is Json => { if (!(myObject && typeof myObject === 'object')) return false; const obj = myObject as { type?: unknown }; return 'type' in obj && obj.type === 'something'; };
方案3:结合类型定义的严谨检查
如果Json类型明确包含type: 'something',可以显式排除null(因为typeof null === 'object'),再做属性检查:
type Json = { type: 'something' } & Record<string, unknown>; const isJson = (myObject: unknown): myObject is Json => { return ( typeof myObject === 'object' && myObject !== null && 'type' in myObject && (myObject as Json).type === 'something' ); };
报错原因说明
开启strict模式后,TypeScript对object类型的属性访问做了严格限制——object仅代表非原始值,不包含任何已知属性,因此直接访问myObject.type会触发编译错误。上述方案通过类型断言或控制流拆分,让TypeScript认可属性的存在,同时维持代码的简洁性。
内容的提问来源于stack exchange,提问作者sir-haver
相关产品推荐
相关产品推荐

