如何用TypeScript实现类似RTK Query useQuery的自动类型窄化?
解决自定义Hook中isConnected与userInfo的类型关联问题
要实现类似RTK Query中useQuery的类型关联效果(通过状态标识自动推断数据的可选性),核心是用TypeScript区分联合类型把isConnected和userInfo的类型绑定起来,让TypeScript能通过状态值自动窄化数据类型。
1. 定义区分联合类型
先给Hook的返回值明确两种状态的结构:
// 定义两种互斥的返回状态类型 type UserProfileResult = | { isConnected: true; userInfo: TUserInfo } | { isConnected: false; userInfo: undefined };
2. 调整自定义Hook的实现
修改Hook的返回逻辑,让它返回上述联合类型,无需手动断言(TypeScript会自动做类型窄化):
export const useGetUserProfile = (): UserProfileResult => { const userInfo = useSelector(selectUserInfo); // 当userInfo存在时,返回已连接状态 if (userInfo !== undefined) { return { isConnected: true, userInfo }; } // 否则返回未连接状态 return { isConnected: false, userInfo: undefined }; };
注:如果
selectUserInfo的返回类型是TUserInfo | undefined,当判断userInfo !== undefined时,TypeScript会自动把userInfo的类型窄化为TUserInfo,不需要额外的类型断言。
3. 使用Hook的正确姿势
现在使用Hook时,只要通过isConnected做判断,TypeScript就能自动识别userInfo的类型,不会再报“'userInfo' is possibly 'undefined'”的错误:
const { isConnected, userInfo } = useGetUserProfile(); // 写法1:if分支判断 let displayName = '!'; if (isConnected) { // 此处userInfo自动被推断为TUserInfo,可直接访问属性 displayName = ' ' + userInfo.firstName; } // 写法2:三元表达式 const displayName = isConnected ? ' ' + userInfo.firstName : '!';
原理说明
原来的Hook返回的是普通对象类型,TypeScript无法关联isConnected和userInfo的类型关系——它只知道isConnected是布尔值,userInfo是可选值,但不知道两者的依赖关系。而区分联合类型明确了两种互斥的状态组合,TypeScript能基于isConnected的取值自动推断对应的userInfo类型。
内容的提问来源于stack exchange,提问作者Nguyễn Minh
相关产品推荐
相关产品推荐

