T
TanStack2mo ago
unwilling-turquoise

obscure getKey type error on collection options

If I have a property in my schema that I have chosen as id for queryCollectionOptions and it is optional then I see a long type error on the entire config object (inside queryCollectionOptions)
const schemaExample = z.object({
id: z.string().uuid().optional(),
// ...
});
type SchemaExample = z.infer<typeof schemaExample>;

// Define collection with persistence handlers
const exampleCollection = createCollection(
queryCollectionOptions<SchemaExample>({
queryKey: ['examples'],
queryFn: ({ queryKey }) => [],
queryClient,
getKey: (item) => item.id,
}),
);
const schemaExample = z.object({
id: z.string().uuid().optional(),
// ...
});
type SchemaExample = z.infer<typeof schemaExample>;

// Define collection with persistence handlers
const exampleCollection = createCollection(
queryCollectionOptions<SchemaExample>({
queryKey: ['examples'],
queryFn: ({ queryKey }) => [],
queryClient,
getKey: (item) => item.id,
}),
);
No overload matches this call.
The last overload gave the following error.
Argument of type 'CollectionConfig<Record<string, unknown>, string | number, { id?: string | undefined; }, UtilsRecord> & { schema: { id?: string | undefined; }; utils: QueryCollectionUtils<...>; }' is not assignable to parameter of type 'CollectionConfig<Record<string, unknown>, string | number, never, UtilsRecord> & { schema?: undefined; utils?: (UtilsRecord & QueryCollectionUtils<...>) | undefined; } & SingleResult'.
Type 'CollectionConfig<Record<string, unknown>, string | number, { id?: string | undefined; }, UtilsRecord> & { schema: { id?: string | undefined; }; utils: QueryCollectionUtils<...>; }' is not assignable to type 'CollectionConfig<Record<string, unknown>, string | number, never, UtilsRecord>'.
Types of property 'schema' are incompatible.
Type '{ id?: string | undefined; }' is not assignable to type 'undefined'.ts(2769)
index.d.ts(106, 25): The last overload is declared here.
⚠ Error (TS2769) | No overload matches this call.
No overload matches this call.
The last overload gave the following error.
Argument of type 'CollectionConfig<Record<string, unknown>, string | number, { id?: string | undefined; }, UtilsRecord> & { schema: { id?: string | undefined; }; utils: QueryCollectionUtils<...>; }' is not assignable to parameter of type 'CollectionConfig<Record<string, unknown>, string | number, never, UtilsRecord> & { schema?: undefined; utils?: (UtilsRecord & QueryCollectionUtils<...>) | undefined; } & SingleResult'.
Type 'CollectionConfig<Record<string, unknown>, string | number, { id?: string | undefined; }, UtilsRecord> & { schema: { id?: string | undefined; }; utils: QueryCollectionUtils<...>; }' is not assignable to type 'CollectionConfig<Record<string, unknown>, string | number, never, UtilsRecord>'.
Types of property 'schema' are incompatible.
Type '{ id?: string | undefined; }' is not assignable to type 'undefined'.ts(2769)
index.d.ts(106, 25): The last overload is declared here.
⚠ Error (TS2769) | No overload matches this call.
I understand the error, but why isn't the error related only to the getKey property instead of the entire config?)
2 Replies
conscious-sapphire
conscious-sapphire2mo ago
Some of the type errors can get quite complex, we need to look how to improve these. In this case I think if you configure the Zod schema to have a default id it will work. Zod schemas have input and output types, the output type is the one used for the collection type, and the input type is used for the insert/update/delete methods. It is expected that the id is not optional in the output type as it can't be optional on the collection. If you want to have server driven ids that are allocated when persisting to your api, then you still need to provide a local temporary id for the row. But in your case you have a uuid, and so can safely allocate it on the client. I also notice you are not passing the Zod schema to the collection just inferi f its type, you can pass it to the collection so that it uses it for validation:
const schemaExample = z.object({
id: z.string().uuid().default(() => crypto.randomUUID()),
// ...
});
type SchemaExample = z.infer<typeof schemaExample>;

const exampleCollection = createCollection(
queryCollectionOptions<SchemaExample>({
queryKey: ['examples'],
queryFn: async () => {
const rows = []; // load raw items
return rows.map(r => schemaExample.parse(r));
},
queryClient,
getKey: (item) => item.id,
schema: schemaExample
}),
);
const schemaExample = z.object({
id: z.string().uuid().default(() => crypto.randomUUID()),
// ...
});
type SchemaExample = z.infer<typeof schemaExample>;

const exampleCollection = createCollection(
queryCollectionOptions<SchemaExample>({
queryKey: ['examples'],
queryFn: async () => {
const rows = []; // load raw items
return rows.map(r => schemaExample.parse(r));
},
queryClient,
getKey: (item) => item.id,
schema: schemaExample
}),
);
unwilling-turquoise
unwilling-turquoiseOP5w ago
Thank u @samwillis When I use your code example I still see the error)
No overload matches this call.
The last overload gave the following error.
Argument of type 'CollectionConfig<Record<string, unknown>, string | number, { id: string; }, UtilsRecord> & { schema: { id: string; }; utils: QueryCollectionUtils<Record<string, unknown>, string | number, Record<...>, unknown>; }' is not assignable to parameter of type 'CollectionConfig<Record<string, unknown>, string | number, never, UtilsRecord> & { schema?: undefined; utils?: (UtilsRecord & QueryCollectionUtils<...>) | undefined; } & SingleResult'.
Type 'CollectionConfig<Record<string, unknown>, string | number, { id: string; }, UtilsRecord> & { schema: { id: string; }; utils: QueryCollectionUtils<Record<string, unknown>, string | number, Record<...>, unknown>; }' is not assignable to type 'CollectionConfig<Record<string, unknown>, string | number, never, UtilsRecord>'.
Types of property 'schema' are incompatible.
Type '{ id: string; }' is not assignable to type 'undefined'.ts(2769)
No overload matches this call.
The last overload gave the following error.
Argument of type 'CollectionConfig<Record<string, unknown>, string | number, { id: string; }, UtilsRecord> & { schema: { id: string; }; utils: QueryCollectionUtils<Record<string, unknown>, string | number, Record<...>, unknown>; }' is not assignable to parameter of type 'CollectionConfig<Record<string, unknown>, string | number, never, UtilsRecord> & { schema?: undefined; utils?: (UtilsRecord & QueryCollectionUtils<...>) | undefined; } & SingleResult'.
Type 'CollectionConfig<Record<string, unknown>, string | number, { id: string; }, UtilsRecord> & { schema: { id: string; }; utils: QueryCollectionUtils<Record<string, unknown>, string | number, Record<...>, unknown>; }' is not assignable to type 'CollectionConfig<Record<string, unknown>, string | number, never, UtilsRecord>'.
Types of property 'schema' are incompatible.
Type '{ id: string; }' is not assignable to type 'undefined'.ts(2769)
Here's the code that I just pasted into mine for testing:
import { createCollection } from '@tanstack/vue-db';
import { queryCollectionOptions, QueryCollectionConfig } from '@tanstack/query-db-collection';
import { queryClient } from '@/query';
import { z } from 'zod';

const schemaExample = z.object({
id: z
.string()
.uuid()
.default(() => crypto.randomUUID()),
// ...
});
type SchemaExample = z.infer<typeof schemaExample>;

const exampleCollection = createCollection(
queryCollectionOptions<SchemaExample>({
queryKey: ['examples'],
queryFn: async () => {
const rows: any[] = []; // load raw items
return rows.map((r) => schemaExample.parse(r));
},
queryClient,
getKey: (item) => item.id,
schema: schemaExample,
}),
);
import { createCollection } from '@tanstack/vue-db';
import { queryCollectionOptions, QueryCollectionConfig } from '@tanstack/query-db-collection';
import { queryClient } from '@/query';
import { z } from 'zod';

const schemaExample = z.object({
id: z
.string()
.uuid()
.default(() => crypto.randomUUID()),
// ...
});
type SchemaExample = z.infer<typeof schemaExample>;

const exampleCollection = createCollection(
queryCollectionOptions<SchemaExample>({
queryKey: ['examples'],
queryFn: async () => {
const rows: any[] = []; // load raw items
return rows.map((r) => schemaExample.parse(r));
},
queryClient,
getKey: (item) => item.id,
schema: schemaExample,
}),
);
In order not to see the error, I have to remove the schema property I realized that I can EITHER use a type for queryCollectionOptions OR use the schema property without specifying the type at the beginning.

Did you find this page helpful?