TypeScript条件检查后无法推断类型含指定属性的问题解决
TypeScript条件检查后无法识别data.token属性的解决方案
问题代码
type MyFunctions = { play(): void pause(args: { reset: boolean }): void stop(args: { restart: boolean }): void } type AuthStruct = { [K in keyof MyFunctions]: { requiresAuth: boolean } } const auth = { play: { requiresAuth: true }, pause: { requiresAuth: true }, stop: { requiresAuth: false } } as const satisfies AuthStruct type Auth = typeof auth type FunctionParameters<K extends keyof MyFunctions> = Parameters< MyFunctions[K] >[0] extends undefined ? never : Parameters<MyFunctions[K]>[0] type Data<K extends keyof MyFunctions> = (FunctionParameters<K> extends never ? {} : FunctionParameters<K> ) & ( Auth[K] extends { requiresAuth: true } ? { token: string } : {} ) function runFunction<F extends keyof MyFunctions>( func: F, data: Data<F> ) { if(auth[func].requiresAuth) { data.token // 此处编译器无法识别token属性 } }
问题描述
执行if(auth[func].requiresAuth)条件检查后,TypeScript编译器无法识别data包含token属性,甚至用data.token!强制断言也无效,该如何解决?
解决方案
原因分析
TypeScript无法通过auth[func].requiresAuth的运行时检查,反向推导泛型F的具体类型分支。auth是const断言后的常量,但泛型F是keyof MyFunctions的子集,编译器无法将auth[F]['requiresAuth']的布尔值与Data<F>的结构建立关联,因此无法细化data的类型。
具体解决方法:使用类型守卫函数
编写一个自定义类型守卫,将func的类型与requiresAuth的布尔值绑定,让编译器能通过条件检查细化data的类型:
// 自定义类型守卫:判断当前func是否需要认证 function requiresAuth<F extends keyof MyFunctions>( func: F ): func is Extract<F, { [K in keyof MyFunctions]: Auth[K]['requiresAuth'] extends true ? K : never }[keyof MyFunctions]> { return auth[func].requiresAuth; } // 修改后的runFunction function runFunction<F extends keyof MyFunctions>( func: F, data: Data<F> ) { if(requiresAuth(func)) { data.token; // 编译器现在能正确识别token属性 console.log(data.token); } else { // 此处data不包含token属性,编译器也能正确推断 console.log(data); } }
原理说明
类型守卫函数requiresAuth返回布尔值的同时,告诉编译器:当返回true时,func的类型是MyFunctions中所有requiresAuth为true的键(即'play'|'pause')。此时编译器会自动将Data<F>细化为包含token的类型分支,从而正确识别data.token。
内容的提问来源于stack exchange,提问作者Riccardo Perego
相关产品推荐
相关产品推荐

