如何编写类型断言函数检查数组中所有Query是否均为Success状态?
解决TypeScript中isAllSuccess函数的类型断言问题
你遇到的错误是因为泛型约束和类型断言的结构不兼容,导致TypeScript无法确认断言类型可以分配给参数类型。下面是具体的分析和修复方案:
错误原因
- 原泛型
T extends Array<Query<any>>过于宽泛,没有区分数组和元组的类型细节,导致TypeScript无法正确推断每个元素的具体Success类型。 - 断言类型
{ [I in keyof T]: Success<T[I]> }存在逻辑问题:T[I]是Query<any>,生成的是Success<Query<any>>,而非你需要的Success<U>(U是原Query的TData类型)。 readonly [...T]的写法和断言类型的数组结构不兼容,触发了TypeScript的类型分配检查错误。
修复方案
调整泛型约束和类型断言的写法,让TypeScript能正确提取每个Query元素的TData类型,并生成对应的Success元组类型:
type Success<T> = { status: 'success', data: T }; type Loading = { status: 'loading' }; type Query<T> = Success<T> | Loading; const isAllSuccess = <T extends readonly Query<any>[]>( queries: T ): queries is { [I in keyof T]: T[I] extends Query<infer U> ? Success<U> : never } => { if (queries.length === 0) return false; return queries.every((q) => q.status === "success"); };
代码解释
- 泛型约束:
T extends readonly Query<any>[]覆盖了普通数组、元组以及只读数组的场景,确保参数可以是任意Query类型的集合。 - 类型断言:使用条件类型
T[I] extends Query<infer U> ? Success<U> : never,自动提取每个Query元素中隐含的TData类型U,将每个元素的类型窄化为对应的Success<U>,完美匹配你的需求。 - 兼容性修复:直接使用
T作为参数类型,避免了readonly [...T]带来的结构冲突,让TypeScript认可断言类型和参数类型的兼容性。
验证示例
// 模拟接口返回类型 type User = { id: number; name: string }; type Article = { title: string; content: string }; // 模拟异步请求钩子 const useFetchUser = (): Query<User> => ({ status: 'success', data: { id: 1, name: 'Alice' } }); const useFetchArticle = (): Query<Article> => ({ status: 'success', data: { title: 'TS技巧', content: '类型窄化' } }); const userQuery = useFetchUser(); const articleQuery = useFetchArticle(); if (isAllSuccess([userQuery, articleQuery])) { // 此处userQuery自动推断为Success<User>,articleQuery为Success<Article> console.log(userQuery.data.name, articleQuery.data.title); }
内容的提问来源于stack exchange,提问作者Jacques Visser
相关产品推荐
相关产品推荐

