Skip to content

Commit b487430

Browse files
authored
fix types when selecting objects such as dates (#524)
1 parent b8c3bb3 commit b487430

File tree

3 files changed

+79
-4
lines changed

3 files changed

+79
-4
lines changed

.changeset/lucky-years-wish.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@tanstack/db": patch
3+
---
4+
5+
Fix a bug where selecting a prop that used a built in object such as a Date would result in incorrect types in the result object.

packages/db/src/query/builder/types.ts

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -500,20 +500,20 @@ export type Ref<T = any> = {
500500
[K in keyof T]: IsNonExactOptional<T[K]> extends true
501501
? IsNonExactNullable<T[K]> extends true
502502
? // Both optional and nullable
503-
NonNullable<T[K]> extends Record<string, any>
503+
IsPlainObject<NonNullable<T[K]>> extends true
504504
? Ref<NonNullable<T[K]>> | undefined
505505
: RefLeaf<NonNullable<T[K]>> | undefined
506506
: // Optional only
507-
NonUndefined<T[K]> extends Record<string, any>
507+
IsPlainObject<NonUndefined<T[K]>> extends true
508508
? Ref<NonUndefined<T[K]>> | undefined
509509
: RefLeaf<NonUndefined<T[K]>> | undefined
510510
: IsNonExactNullable<T[K]> extends true
511511
? // Nullable only
512-
NonNull<T[K]> extends Record<string, any>
512+
IsPlainObject<NonNull<T[K]>> extends true
513513
? Ref<NonNull<T[K]>> | null
514514
: RefLeaf<NonNull<T[K]>> | null
515515
: // Required
516-
T[K] extends Record<string, any>
516+
IsPlainObject<T[K]> extends true
517517
? Ref<T[K]>
518518
: RefLeaf<T[K]>
519519
} & RefLeaf<T>
@@ -825,3 +825,48 @@ export type WithResult<TContext extends Context, TResult> = Prettify<
825825
export type Prettify<T> = {
826826
[K in keyof T]: T[K]
827827
} & {}
828+
829+
/**
830+
* IsPlainObject - Utility type to check if T is a plain object
831+
*/
832+
type IsPlainObject<T> = T extends unknown
833+
? T extends object
834+
? T extends ReadonlyArray<any>
835+
? false
836+
: T extends JsBuiltIns
837+
? false
838+
: true
839+
: false
840+
: false
841+
842+
/**
843+
* JsBuiltIns - List of JavaScript built-ins
844+
*/
845+
type JsBuiltIns =
846+
| ArrayBuffer
847+
| ArrayBufferLike
848+
| AsyncGenerator<any, any, any>
849+
| BigInt64Array
850+
| BigUint64Array
851+
| DataView
852+
| Date
853+
| Error
854+
| Float32Array
855+
| Float64Array
856+
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
857+
| Function
858+
| Generator<any, any, any>
859+
| Int16Array
860+
| Int32Array
861+
| Int8Array
862+
| Map<any, any>
863+
| Promise<any>
864+
| RegExp
865+
| Set<any>
866+
| string
867+
| Uint16Array
868+
| Uint32Array
869+
| Uint8Array
870+
| Uint8ClampedArray
871+
| WeakMap<any, any>
872+
| WeakSet<any>

packages/db/tests/query/select.test-d.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import { upper } from "../../src/query/builder/functions.js"
77
type User = {
88
id: number
99
name: string
10+
joinedDate: Date
11+
something: string
1012
profile: {
1113
bio: string
1214
preferences: {
@@ -53,6 +55,29 @@ describe(`select types`, () => {
5355
expectTypeOf(results).toEqualTypeOf<Expected>()
5456
})
5557

58+
test(`works with js built-ins objects`, () => {
59+
const users = createUsers()
60+
const col = createLiveQueryCollection((q) =>
61+
q.from({ u: users }).select(({ u }) => ({
62+
id: u.id,
63+
joinedDate: u.joinedDate,
64+
name: u.name,
65+
something: u.something,
66+
}))
67+
)
68+
69+
type Expected = {
70+
id: number
71+
joinedDate: Date
72+
name: string
73+
something: string
74+
}
75+
76+
const results = col.toArray[0]!
77+
78+
expectTypeOf(results).toEqualTypeOf<Expected>()
79+
})
80+
5681
test(`nested object selection infers nested result type`, () => {
5782
const users = createUsers()
5883
const col = createLiveQueryCollection((q) =>

0 commit comments

Comments
 (0)