如何基于部分已知判别式收窄TypeScript可辨识联合类型?
解决React Hook返回值根据功能开关自动收窄类型的方案
核心思路是用泛型捕获入参的具体类型,配合条件类型推导返回值结构,让TypeScript能把入参的功能开关状态和返回值属性做关联,而非依赖可辨识联合的自动收窄(联合类型本身无法在函数内部关联入参和返回的分支)。
步骤1:定义基础类型与工具类型
先拆分基础参数、各功能专属参数,再编写工具类型根据入参开关状态生成对应返回类型:
// 基础共享参数 type BaseArgs = { sharedProp: string; }; // FeatureOne开启时的专属必填参数 type FeatureOneEnabledArgs = { isFeatureOneEnabled: true; featureOneProp: string; }; // FeatureOne关闭时的参数(开关可选或设为false) type FeatureOneDisabledArgs = { isFeatureOneEnabled?: false; }; // 入参的泛型约束:合并基础参数与对应功能分支 type CustomHookArgs<T extends boolean | undefined = undefined> = BaseArgs & (T extends true ? FeatureOneEnabledArgs : FeatureOneDisabledArgs); // 根据入参开关推导返回值的工具类型 type CustomHookReturn<T extends CustomHookArgs> = { sharedState: number; } & (T extends { isFeatureOneEnabled: true } ? { someFeatureOneThings: string; } : {});
步骤2:用泛型实现Hook
通过泛型捕获调用时的具体入参类型,让返回值自动匹配推导结果:
import { useState } from 'react'; function useCustomHook<T extends CustomHookArgs>(args: T): CustomHookReturn<T> { const [sharedState] = useState(0); if (args.isFeatureOneEnabled) { return { sharedState, someFeatureOneThings: args.featureOneProp.toUpperCase() } as CustomHookReturn<T>; } return { sharedState } as CustomHookReturn<T>; }
步骤3:调用验证
传入不同开关状态时,返回值会自动收窄类型,无需额外条件判断:
// 开启FeatureOne:返回值明确包含someFeatureOneThings,类型为string const { sharedState, someFeatureOneThings } = useCustomHook({ sharedProp: 'test', isFeatureOneEnabled: true, featureOneProp: 'foo' }); console.log(someFeatureOneThings); // 无类型报错 // 关闭FeatureOne:返回值不包含someFeatureOneThings,访问会直接报错 const { sharedState: disabledState } = useCustomHook({ sharedProp: 'test', isFeatureOneEnabled: false }); // 此处若访问someFeatureOneThings,TypeScript直接提示属性不存在
原方案问题说明
之前用可辨识联合作为入参时,函数返回值只能是所有联合分支的合并类型,TypeScript无法自动关联“当前传入的是联合某一分支”与返回值的对应关系。而泛型可精准捕获调用时的入参类型,配合条件类型就能实现返回值的自动收窄。
内容的提问来源于stack exchange,提问作者Mike Turley
相关产品推荐
相关产品推荐

