Skip to content

Commit f6a0863

Browse files
committed
fix(types): improve exact safety
1 parent ecbc99b commit f6a0863

File tree

2 files changed

+29
-22
lines changed

2 files changed

+29
-22
lines changed

src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ import type { UnionToIntersection } from 'type-fest'
2727
type QueryType = 'query' | 'infinite'
2828
export type TRPCQueryKey = [readonly string[], { input?: unknown; type?: QueryType }?]
2929

30+
export { type Exact } from './types'
31+
3032
function getQueryKey(path: string[], input: unknown, type?: QueryType): TRPCQueryKey {
3133
const splitPath = path.flatMap((part) => part.split('.'))
3234

src/types.ts

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,24 @@ type TRPCSubscriptionObserver<TValue, TError> = {
3434
}
3535

3636
type ArrayElement<T> = T extends readonly unknown[] ? T[number] : never
37-
export type Exact<Shape, T extends Shape> = Shape extends void
38-
? void
39-
: {
40-
[Key in keyof T]: Key extends keyof Shape
41-
? T[Key] extends Date
42-
? T[Key]
43-
: T[Key] extends unknown[]
44-
? Array<Exact<ArrayElement<Shape[Key]>, ArrayElement<T[Key]>>>
45-
: T[Key] extends object
46-
? Exact<Shape[Key], T[Key]>
47-
: T[Key]
48-
: never
49-
}
37+
type Primitive = null | undefined | string | number | boolean | symbol | bigint
38+
export type Exact<Shape, T extends Shape> = Shape extends Primitive
39+
? Shape
40+
: Shape extends object
41+
? {
42+
[Key in keyof T]: Key extends keyof Shape
43+
? T[Key] extends Date
44+
? T[Key]
45+
: T[Key] extends unknown[]
46+
? Array<Exact<ArrayElement<Shape[Key]>, ArrayElement<T[Key]>>>
47+
: T[Key] extends readonly unknown[]
48+
? ReadonlyArray<Exact<ArrayElement<Shape[Key]>, ArrayElement<T[Key]>>>
49+
: T[Key] extends object
50+
? Exact<Shape[Key], T[Key]>
51+
: T[Key]
52+
: never
53+
}
54+
: Shape
5055

5156
export type DecorateProcedure<
5257
TProcedure extends AnyTRPCProcedure,
@@ -59,7 +64,7 @@ export type DecorateProcedure<
5964
TData extends TQueryFnData,
6065
TQueryData extends TQueryFnData,
6166
TQueryKey extends QueryKey,
62-
TInput,
67+
TInput extends inferProcedureInput<TProcedure>,
6368
>(
6469
input: MaybeRefOrGetter<Exact<inferProcedureInput<TProcedure>, TInput>>,
6570
opts?: MaybeRefOrGetter<
@@ -72,18 +77,18 @@ export type DecorateProcedure<
7277
}
7378
>,
7479
) => UseQueryReturnType<TData, TError>
75-
query: <TInput>(
80+
query: <TInput extends inferProcedureInput<TProcedure>>(
7681
input: Exact<inferProcedureInput<TProcedure>, TInput>,
7782
opts?: ProcedureOptions,
7883
) => Promise<inferTransformedProcedureOutput<TRouter, TProcedure>>
79-
invalidate: <TInput>(
84+
invalidate: <TInput extends inferProcedureInput<TProcedure>>(
8085
input?: MaybeRefOrGetter<Exact<inferProcedureInput<TProcedure>, TInput>>,
8186
) => Promise<void>
82-
setQueryData: <TInput>(
87+
setQueryData: <TInput extends inferProcedureInput<TProcedure>>(
8388
updater: inferTransformedProcedureOutput<TRouter, TProcedure>,
8489
input?: MaybeRefOrGetter<Exact<inferProcedureInput<TProcedure>, TInput>>,
8590
) => ReturnType<QueryClient['setQueryData']>
86-
key: <TInput>(
91+
key: <TInput extends inferProcedureInput<TProcedure>>(
8792
input?: MaybeRefOrGetter<Exact<inferProcedureInput<TProcedure>, TInput>>,
8893
) => QueryKey
8994
} & (TProcedure['_def']['$types']['input'] extends { cursor?: infer CursorType }
@@ -94,7 +99,7 @@ export type DecorateProcedure<
9499
TData extends InfiniteData<TQueryFnData>,
95100
TQueryData extends TQueryFnData,
96101
TQueryKey extends QueryKey,
97-
TInput,
102+
TInput extends inferProcedureInput<TProcedure>,
98103
>(
99104
input: MaybeRefOrGetter<Exact<Omit<inferProcedureInput<TProcedure>, 'cursor'>, TInput>>,
100105
opts?: MaybeRefOrGetter<
@@ -115,7 +120,7 @@ export type DecorateProcedure<
115120
: object)
116121
: TProcedure extends AnyTRPCMutationProcedure
117122
? {
118-
mutate: <TInput>(
123+
mutate: <TInput extends inferProcedureInput<TProcedure>>(
119124
input: Exact<inferProcedureInput<TProcedure>, TInput>,
120125
opts?: ProcedureOptions,
121126
) => Promise<inferTransformedProcedureOutput<TRouter, TProcedure>>
@@ -135,7 +140,7 @@ export type DecorateProcedure<
135140
}
136141
: TProcedure extends AnyTRPCSubscriptionProcedure
137142
? {
138-
subscribe: <TInput>(
143+
subscribe: <TInput extends inferProcedureInput<TProcedure>>(
139144
input: Exact<inferProcedureInput<TProcedure>, TInput>,
140145
opts: ProcedureOptions &
141146
Partial<
@@ -145,7 +150,7 @@ export type DecorateProcedure<
145150
>
146151
>,
147152
) => Unsubscribable
148-
useSubscription: <TInput>(
153+
useSubscription: <TInput extends inferProcedureInput<TProcedure>>(
149154
input: MaybeRefOrGetter<Exact<inferProcedureInput<TProcedure>, TInput>>,
150155
opts: ProcedureOptions &
151156
Partial<

0 commit comments

Comments
 (0)