-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(angular-query-experimental): allow returning undefined in initial…
…Data function Fix incorrect types that disallowed that. This is necessary because the initialData function can typically read cache synchronously and need to be able to signal to the query if there is a cache miss and an actual fetch needs to be deployed. No breaking changes, any code that worked before should work now as well.
- Loading branch information
1 parent
7368bd0
commit fc00927
Showing
2 changed files
with
112 additions
and
88 deletions.
There are no files selected for viewing
171 changes: 95 additions & 76 deletions
171
packages/angular-query-experimental/src/__tests__/query-options.test-d.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,127 +1,146 @@ | ||
import { assertType, describe, expectTypeOf } from 'vitest' | ||
import { QueryClient } from '@tanstack/query-core' | ||
import { dataTagSymbol } from '@tanstack/query-core' | ||
import { queryOptions } from '../query-options' | ||
import { injectQuery } from '../inject-query' | ||
import type { Signal } from '@angular/core' | ||
|
||
describe('queryOptions', () => { | ||
test('should not allow excess properties', () => { | ||
import { assertType, describe, expectTypeOf } from "vitest"; | ||
import { QueryClient } from "@tanstack/query-core"; | ||
import { dataTagSymbol } from "@tanstack/query-core"; | ||
import { queryOptions } from "../query-options"; | ||
import { injectQuery } from "../inject-query"; | ||
import type { Signal } from "@angular/core"; | ||
|
||
describe("queryOptions", () => { | ||
test("should not allow excess properties", () => { | ||
return queryOptions({ | ||
queryKey: ['key'], | ||
queryKey: ["key"], | ||
queryFn: () => Promise.resolve(5), | ||
// @ts-expect-error this is a good error, because stallTime does not exist! | ||
stallTime: 1000, | ||
}) | ||
}) | ||
}); | ||
}); | ||
|
||
test('should infer types for callbacks', () => { | ||
test("should infer types for callbacks", () => { | ||
return queryOptions({ | ||
queryKey: ['key'], | ||
queryKey: ["key"], | ||
queryFn: () => Promise.resolve(5), | ||
staleTime: 1000, | ||
select: (data) => { | ||
expectTypeOf(data).toEqualTypeOf<number>() | ||
expectTypeOf(data).toEqualTypeOf<number>(); | ||
}, | ||
}) | ||
}) | ||
}) | ||
|
||
test('should work when passed to injectQuery', () => { | ||
}); | ||
}); | ||
|
||
test("should allow undefined response in initialData", () => { | ||
return (id: string | null) => | ||
queryOptions({ | ||
queryKey: ["todo", id], | ||
queryFn: () => | ||
Promise.resolve({ | ||
id: "1", | ||
title: "Do Laundry", | ||
}), | ||
initialData: () => | ||
!id | ||
? undefined | ||
: { | ||
id, | ||
title: "Initial Data", | ||
}, | ||
}); | ||
}); | ||
}); | ||
|
||
test("should work when passed to injectQuery", () => { | ||
const options = queryOptions({ | ||
queryKey: ['key'], | ||
queryKey: ["key"], | ||
queryFn: () => Promise.resolve(5), | ||
}) | ||
}); | ||
|
||
const { data } = injectQuery(() => options) | ||
expectTypeOf(data).toEqualTypeOf<Signal<number | undefined>>() | ||
}) | ||
const { data } = injectQuery(() => options); | ||
expectTypeOf(data).toEqualTypeOf<Signal<number | undefined>>(); | ||
}); | ||
|
||
test('should work when passed to fetchQuery', () => { | ||
test("should work when passed to fetchQuery", () => { | ||
const options = queryOptions({ | ||
queryKey: ['key'], | ||
queryKey: ["key"], | ||
queryFn: () => Promise.resolve(5), | ||
}) | ||
}); | ||
|
||
const data = new QueryClient().fetchQuery(options) | ||
assertType<Promise<number>>(data) | ||
}) | ||
const data = new QueryClient().fetchQuery(options); | ||
assertType<Promise<number>>(data); | ||
}); | ||
|
||
test('should tag the queryKey with the result type of the QueryFn', () => { | ||
test("should tag the queryKey with the result type of the QueryFn", () => { | ||
const { queryKey } = queryOptions({ | ||
queryKey: ['key'], | ||
queryKey: ["key"], | ||
queryFn: () => Promise.resolve(5), | ||
}) | ||
assertType<number>(queryKey[dataTagSymbol]) | ||
}) | ||
}); | ||
assertType<number>(queryKey[dataTagSymbol]); | ||
}); | ||
|
||
test('should tag the queryKey even if no promise is returned', () => { | ||
test("should tag the queryKey even if no promise is returned", () => { | ||
const { queryKey } = queryOptions({ | ||
queryKey: ['key'], | ||
queryKey: ["key"], | ||
queryFn: () => 5, | ||
}) | ||
assertType<number>(queryKey[dataTagSymbol]) | ||
}) | ||
}); | ||
assertType<number>(queryKey[dataTagSymbol]); | ||
}); | ||
|
||
test('should tag the queryKey with unknown if there is no queryFn', () => { | ||
test("should tag the queryKey with unknown if there is no queryFn", () => { | ||
const { queryKey } = queryOptions({ | ||
queryKey: ['key'], | ||
}) | ||
queryKey: ["key"], | ||
}); | ||
|
||
assertType<unknown>(queryKey[dataTagSymbol]) | ||
}) | ||
assertType<unknown>(queryKey[dataTagSymbol]); | ||
}); | ||
|
||
test('should tag the queryKey with the result type of the QueryFn if select is used', () => { | ||
test("should tag the queryKey with the result type of the QueryFn if select is used", () => { | ||
const { queryKey } = queryOptions({ | ||
queryKey: ['key'], | ||
queryKey: ["key"], | ||
queryFn: () => Promise.resolve(5), | ||
select: (data) => data.toString(), | ||
}) | ||
}); | ||
|
||
assertType<number>(queryKey[dataTagSymbol]) | ||
}) | ||
assertType<number>(queryKey[dataTagSymbol]); | ||
}); | ||
|
||
test('should return the proper type when passed to getQueryData', () => { | ||
test("should return the proper type when passed to getQueryData", () => { | ||
const { queryKey } = queryOptions({ | ||
queryKey: ['key'], | ||
queryKey: ["key"], | ||
queryFn: () => Promise.resolve(5), | ||
}) | ||
}); | ||
|
||
const queryClient = new QueryClient() | ||
const data = queryClient.getQueryData(queryKey) | ||
const queryClient = new QueryClient(); | ||
const data = queryClient.getQueryData(queryKey); | ||
|
||
expectTypeOf(data).toEqualTypeOf<number | undefined>() | ||
}) | ||
expectTypeOf(data).toEqualTypeOf<number | undefined>(); | ||
}); | ||
|
||
test('should properly type updaterFn when passed to setQueryData', () => { | ||
test("should properly type updaterFn when passed to setQueryData", () => { | ||
const { queryKey } = queryOptions({ | ||
queryKey: ['key'], | ||
queryKey: ["key"], | ||
queryFn: () => Promise.resolve(5), | ||
}) | ||
}); | ||
|
||
const queryClient = new QueryClient() | ||
const queryClient = new QueryClient(); | ||
const data = queryClient.setQueryData(queryKey, (prev) => { | ||
expectTypeOf(prev).toEqualTypeOf<number | undefined>() | ||
return prev | ||
}) | ||
expectTypeOf(prev).toEqualTypeOf<number | undefined>(); | ||
return prev; | ||
}); | ||
|
||
expectTypeOf(data).toEqualTypeOf<number | undefined>() | ||
}) | ||
expectTypeOf(data).toEqualTypeOf<number | undefined>(); | ||
}); | ||
|
||
test('should properly type value when passed to setQueryData', () => { | ||
test("should properly type value when passed to setQueryData", () => { | ||
const { queryKey } = queryOptions({ | ||
queryKey: ['key'], | ||
queryKey: ["key"], | ||
queryFn: () => Promise.resolve(5), | ||
}) | ||
}); | ||
|
||
const queryClient = new QueryClient() | ||
const queryClient = new QueryClient(); | ||
|
||
// @ts-expect-error value should be a number | ||
queryClient.setQueryData(queryKey, '5') | ||
queryClient.setQueryData(queryKey, "5"); | ||
// @ts-expect-error value should be a number | ||
queryClient.setQueryData(queryKey, () => '5') | ||
queryClient.setQueryData(queryKey, () => "5"); | ||
|
||
const data = queryClient.setQueryData(queryKey, 5) | ||
const data = queryClient.setQueryData(queryKey, 5); | ||
|
||
expectTypeOf(data).toEqualTypeOf<number | undefined>() | ||
}) | ||
expectTypeOf(data).toEqualTypeOf<number | undefined>(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters