Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(react-query): improved TypeScript engine halt due to return type …
…inference in useSuspenseQueries (#911) # Overview fixed: #889 Fixes a bug where the TypeScript engine would hang due to the complex return type of useSuspenseQueries. ## Issue ```ts // build -> dist/useSuspenseQueries.d.ts /** * SuspenseQueriesResults reducer recursively maps type param to results */ type SuspenseQueriesResults<T extends Array<any>, TResult extends Array<any> = [], TDepth extends ReadonlyArray<number> = []> = TDepth['length'] extends MAXIMUM_DEPTH ? Array<UseSuspenseQueryResult> : T extends [] ? [] : T extends [infer Head] ? [...TResult, GetSuspenseResults<Head>] : T extends [infer Head, ...infer Tail] ? SuspenseQueriesResults<[...Tail], [...TResult, GetSuspenseResults<Head>], [...TDepth, 1]> : T extends Array<UseSuspenseQueryOptions<infer TQueryFnData, infer TError, infer TData, any>> ? Array<UseSuspenseQueryResult<unknown extends TData ? TQueryFnData : TData, TError>> : Array<UseSuspenseQueryResult>; declare function useSuspenseQueries<T extends any[]>({ queries, context, }: { queries: readonly [...SuspenseQueriesOptions<T>]; context?: UseQueryOptions['context']; // return type 🤔 }): T extends [] ? [] : T extends [infer Head] ? [GetSuspenseResults<Head>] : T extends [infer Head_1, …infer Tail] ? […Tail] extends infer T_1 ? T_1 extends […Tail] ? T_1 extends [] ? [] : T_1 extends [infer Head] ? [GetSuspenseResults<Head_1>, GetSuspenseResults<Head>] : T_1 extends [infer Head_1, …infer Tail] ? […Tail] extends infer T_2 ? T_2 extends […Tail] ? T_2 extends [] ? [] : T_2 extends [infer Head] ? [GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head>] : T_2 extends [infer Head_1, …infer Tail] ? […Tail] extends infer T_3 ? T_3 extends […Tail] ? T_3 extends [] ? [] : T_3 extends [infer Head] ? [GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head>] : T_3 extends [infer Head_1, …infer Tail] ? […Tail] extends infer T_4 ? T_4 extends […Tail] ? T_4 extends [] ? [] : T_4 extends [infer Head] ? [GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head>] : T_4 extends [infer Head_1, …infer Tail] ? […Tail] extends infer T_5 ? T_5 extends […Tail] ? T_5 extends [] ? [] : T_5 extends [infer Head] ? [GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head>] : T_5 extends [infer Head_1, …infer Tail] ? […Tail] extends infer T_6 ? T_6 extends […Tail] ? T_6 extends [] ? [] : T_6 extends [infer Head] ? [GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head>] : T_6 extends [infer Head_1, …infer Tail] ? […Tail] extends infer T_7 ? T_7 extends […Tail] ? T_7 extends [] ? [] : T_7 extends [infer Head] ? [GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head>] : T_7 extends [infer Head_1, …infer Tail] ? […Tail] extends infer T_8 ? T_8 extends […Tail] ? T_8 extends [] ? [] : T_8 extends [infer Head] ? [GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head>] : T_8 extends [infer Head_1, …infer Tail] ? […Tail] extends infer T_9 ? T_9 extends […Tail] ? T_9 extends [] ? [] : T_9 extends [infer Head] ? [GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head>] : T_9 extends [infer Head_1, …infer Tail] ? […Tail] extends infer T_10 ? T_10 extends […Tail] ? T_10 extends [] ? [] : T_10 extends [infer Head] ? [GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head>] : T_10 extends [infer Head_1, …infer Tail] ? any : T_10 extends UseSuspenseQueryOptions<infer TQueryFnData, infer TError, infer TData, any>[] ? UseSuspenseQueryResult<unknown extends TData ? TQueryFnData : TData, TError>[] : UseSuspenseQueryResult<unknown, unknown>[] : never : never : T_9 extends UseSuspenseQueryOptions<infer TQueryFnData, infer TError, infer TData, any>[] ? UseSuspenseQueryResult<unknown extends TData ? TQueryFnData : TData, TError>[] : UseSuspenseQueryResult<unknown, unknown>[] : never : never : T_8 extends UseSuspenseQueryOptions<infer TQueryFnData, infer TError, infer TData, any>[] ? UseSuspenseQueryResult<unknown extends TData ? TQueryFnData : TData, TError>[] : UseSuspenseQueryResult<unknown, unknown>[] : never : never : T_7 extends UseSuspenseQueryOptions<infer TQueryFnData, infer TError, infer TData, any>[] ? UseSuspenseQueryResult<unknown extends TData ? TQueryFnData : TData, TError>[] : UseSuspenseQueryResult<unknown, unknown>[] : never : never : T_6 extends UseSuspenseQueryOptions<infer TQueryFnData, infer TError, infer TData, any>[] ? UseSuspenseQueryResult<unknown extends TData ? TQueryFnData : TData, TError>[] : UseSuspenseQueryResult<unknown, unknown>[] : never : never : T_5 extends UseSuspenseQueryOptions<infer TQueryFnData, infer TError, infer TData, any>[] ? UseSuspenseQueryResult<unknown extends TData ? TQueryFnData : TData, TError>[] : UseSuspenseQueryResult<unknown, unknown>[] : never : never : T_4 extends UseSuspenseQueryOptions<infer TQueryFnData, infer TError, infer TData, any>[] ? UseSuspenseQueryResult<unknown extends TData ? TQueryFnData : TData, TError>[] : UseSuspenseQueryResult<unknown, unknown>[] : never : never : T_3 extends UseSuspenseQueryOptions<infer TQueryFnData, infer TError, infer TData, any>[] ? UseSuspenseQueryResult<unknown extends TData ? TQueryFnData : TData, TError>[] : UseSuspenseQueryResult<unknown, unknown>[] : never : never : T_2 extends UseSuspenseQueryOptions<infer TQueryFnData, infer TError, infer TData, any>[] ? UseSuspenseQueryResult<unknown extends TData ? TQueryFnData : TData, TError>[] : UseSuspenseQueryResult<unknown, unknown>[] : never : never : T_1 extends UseSuspenseQueryOptions<infer TQueryFnData, infer TError, infer TData, any>[] ? UseSuspenseQueryResult<unknown extends TData ? TQueryFnData : TData, TError>[] : UseSuspenseQueryResult<unknown, unknown>[] : never : never : T extends UseSuspenseQueryOptions<infer TQueryFnData, infer TError, infer TData, any>[] ? UseSuspenseQueryResult<unknown extends TData ? TQueryFnData : TData, TError>[] : UseSuspenseQueryResult<unknown, unknown>[]; export { type SuspenseQueriesOptions, type SuspenseQueriesResults, useSuspenseQueries }; ``` When you check the built type declarations, you'll see that the return type of useSuspenseQueries is determined through very complex type inference. This complexity in the inference process can cause the TypeScript engine to hang. (This issue is also documented in the TypeScript GitHub issues.) - microsoft/TypeScript#38182 ```ts // return type 🤔 T extends [] ? [] : T extends [infer Head] ? [GetSuspenseResults<Head>] : T extends [infer Head_1, …infer Tail] ? […Tail] extends infer T_1 ? T_1 extends […Tail] ? T_1 extends [] ? [] : T_1 extends [infer Head] ? [GetSuspenseResults<Head_1>, GetSuspenseResults<Head>] : T_1 extends [infer Head_1, …infer Tail] ? […Tail] extends infer T_2 ? T_2 extends […Tail] ? T_2 extends [] ? [] : T_2 extends [infer Head] ? [GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head>] : T_2 extends [infer Head_1, …infer Tail] ? […Tail] extends infer T_3 ? T_3 extends […Tail] ? T_3 extends [] ? [] : T_3 extends [infer Head] ? [GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head>] : T_3 extends [infer Head_1, …infer Tail] ? […Tail] extends infer T_4 ? T_4 extends […Tail] ? T_4 extends [] ? [] : T_4 extends [infer Head] ? [GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head>] : T_4 extends [infer Head_1, …infer Tail] ? […Tail] extends infer T_5 ? T_5 extends […Tail] ? T_5 extends [] ? [] : T_5 extends [infer Head] ? [GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head>] : T_5 extends [infer Head_1, …infer Tail] ? […Tail] extends infer T_6 ? T_6 extends […Tail] ? T_6 extends [] ? [] : T_6 extends [infer Head] ? [GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head>] : T_6 extends [infer Head_1, …infer Tail] ? […Tail] extends infer T_7 ? T_7 extends […Tail] ? T_7 extends [] ? [] : T_7 extends [infer Head] ? [GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head>] : T_7 extends [infer Head_1, …infer Tail] ? […Tail] extends infer T_8 ? T_8 extends […Tail] ? T_8 extends [] ? [] : T_8 extends [infer Head] ? [GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head>] : T_8 extends [infer Head_1, …infer Tail] ? […Tail] extends infer T_9 ? T_9 extends […Tail] ? T_9 extends [] ? [] : T_9 extends [infer Head] ? [GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head>] : T_9 extends [infer Head_1, …infer Tail] ? […Tail] extends infer T_10 ? T_10 extends […Tail] ? T_10 extends [] ? [] : T_10 extends [infer Head] ? [GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head_1>, GetSuspenseResults<Head>] : T_10 extends [infer Head_1, …infer Tail] ? any : T_10 extends UseSuspenseQueryOptions<infer TQueryFnData, infer TError, infer TData, any>[] ? UseSuspenseQueryResult<unknown extends TData ? TQueryFnData : TData, TError>[] : UseSuspenseQueryResult<unknown, unknown>[] : never : never : T_9 extends UseSuspenseQueryOptions<infer TQueryFnData, infer TError, infer TData, any>[] ? UseSuspenseQueryResult<unknown extends TData ? TQueryFnData : TData, TError>[] : UseSuspenseQueryResult<unknown, unknown>[] : never : never : T_8 extends UseSuspenseQueryOptions<infer TQueryFnData, infer TError, infer TData, any>[] ? UseSuspenseQueryResult<unknown extends TData ? TQueryFnData : TData, TError>[] : UseSuspenseQueryResult<unknown, unknown>[] : never : never : T_7 extends UseSuspenseQueryOptions<infer TQueryFnData, infer TError, infer TData, any>[] ? UseSuspenseQueryResult<unknown extends TData ? TQueryFnData : TData, TError>[] : UseSuspenseQueryResult<unknown, unknown>[] : never : never : T_6 extends UseSuspenseQueryOptions<infer TQueryFnData, infer TError, infer TData, any>[] ? UseSuspenseQueryResult<unknown extends TData ? TQueryFnData : TData, TError>[] : UseSuspenseQueryResult<unknown, unknown>[] : never : never : T_5 extends UseSuspenseQueryOptions<infer TQueryFnData, infer TError, infer TData, any>[] ? UseSuspenseQueryResult<unknown extends TData ? TQueryFnData : TData, TError>[] : UseSuspenseQueryResult<unknown, unknown>[] : never : never : T_4 extends UseSuspenseQueryOptions<infer TQueryFnData, infer TError, infer TData, any>[] ? UseSuspenseQueryResult<unknown extends TData ? TQueryFnData : TData, TError>[] : UseSuspenseQueryResult<unknown, unknown>[] : never : never : T_3 extends UseSuspenseQueryOptions<infer TQueryFnData, infer TError, infer TData, any>[] ? UseSuspenseQueryResult<unknown extends TData ? TQueryFnData : TData, TError>[] : UseSuspenseQueryResult<unknown, unknown>[] : never : never : T_2 extends UseSuspenseQueryOptions<infer TQueryFnData, infer TError, infer TData, any>[] ? UseSuspenseQueryResult<unknown extends TData ? TQueryFnData : TData, TError>[] : UseSuspenseQueryResult<unknown, unknown>[] : never : never : T_1 extends UseSuspenseQueryOptions<infer TQueryFnData, infer TError, infer TData, any>[] ? UseSuspenseQueryResult<unknown extends TData ? TQueryFnData : TData, TError>[] : UseSuspenseQueryResult<unknown, unknown>[] : never : never : T extends UseSuspenseQueryOptions<infer TQueryFnData, infer TError, infer TData, any>[] ? UseSuspenseQueryResult<unknown extends TData ? TQueryFnData : TData, TError>[] : UseSuspenseQueryResult<unknown, unknown>[]; ``` Currently, the return type is inferred for complex types. ## Improvement ```ts // useSuspenseQueries.ts export function useSuspenseQueries<T extends any[]>({ queries, context, }: { queries: readonly [...SuspenseQueriesOptions<T>] context?: UseQueryOptions['context'] }): SuspenseQueriesResults<T> { return useQueries({ queries: queries.map((query: typeof queries) => ({ ...query, suspense: true })), context, }) as SuspenseQueriesResults<T> } ``` Specify the return type explicitly to prevent TypeScript’s inference from hanging. ```ts // build -> dist/useSuspenseQueries.d.ts /** * SuspenseQueriesResults reducer recursively maps type param to results */ type SuspenseQueriesResults<T extends Array<any>, TResult extends Array<any> = [], TDepth extends ReadonlyArray<number> = []> = TDepth['length'] extends MAXIMUM_DEPTH ? Array<UseSuspenseQueryResult> : T extends [] ? [] : T extends [infer Head] ? [...TResult, GetSuspenseResults<Head>] : T extends [infer Head, ...infer Tail] ? SuspenseQueriesResults<[...Tail], [...TResult, GetSuspenseResults<Head>], [...TDepth, 1]> : T extends Array<UseSuspenseQueryOptions<infer TQueryFnData, infer TError, infer TData, any>> ? Array<UseSuspenseQueryResult<unknown extends TData ? TQueryFnData : TData, TError>> : Array<UseSuspenseQueryResult>; declare function useSuspenseQueries<T extends any[]>({ queries, context, }: { queries: readonly [...SuspenseQueriesOptions<T>]; context?: UseQueryOptions['context']; }): SuspenseQueriesResults<T>; export { type SuspenseQueriesOptions, type SuspenseQueriesResults, useSuspenseQueries }; ``` The complex inference process is replaced with `SuspenseQueriesResults`, simplifying it and preventing the TypeScript engine from hanging. ## PR Checklist - [x] I did below actions if need 1. I read the [Contributing Guide](https://github.com/suspensive/react/blob/main/CONTRIBUTING.md) 2. I added documents and tests. --------- Co-authored-by: Jonghyeon Ko <jonghyeon@toss.im>
- Loading branch information