Skip to content

Commit

Permalink
fix(start): infer input of validator functions (#2808)
Browse files Browse the repository at this point in the history
  • Loading branch information
chorobin authored Nov 21, 2024
1 parent 481bb99 commit 7f8199c
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 31 deletions.
2 changes: 2 additions & 0 deletions packages/react-router/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,8 @@ export type {
AnyValidatorObj,
ResolveValidatorInputFn,
ResolveValidatorOutputFn,
ResolveSearchValidatorInput,
ResolveSearchValidatorInputFn,
Validator,
ValidatorAdapter,
ValidatorObj,
Expand Down
6 changes: 3 additions & 3 deletions packages/react-router/src/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import type {
AnyValidatorAdapter,
AnyValidatorObj,
DefaultValidator,
ResolveValidatorInput,
ResolveSearchValidatorInput,
ResolveValidatorOutput,
StandardSchemaValidator,
ValidatorAdapter,
Expand Down Expand Up @@ -679,7 +679,7 @@ export type ResolveFullSearchSchemaInput<
TSearchValidator,
> = Assign<
InferFullSearchSchemaInput<TParentRoute>,
ResolveValidatorInput<TSearchValidator>
ResolveSearchValidatorInput<TSearchValidator>
>

export type LooseReturnType<T> = T extends (
Expand Down Expand Up @@ -988,7 +988,7 @@ export class Route<
customId: TCustomId
id: TId
searchSchema: ResolveValidatorOutput<TSearchValidator>
searchSchemaInput: ResolveValidatorInput<TSearchValidator>
searchSchemaInput: ResolveSearchValidatorInput<TSearchValidator>
searchValidator: TSearchValidator
fullSearchSchema: ResolveFullSearchSchema<TParentRoute, TSearchValidator>
fullSearchSchemaInput: ResolveFullSearchSchemaInput<
Expand Down
17 changes: 16 additions & 1 deletion packages/react-router/src/validators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,29 @@ export type AnySchema = {}

export type DefaultValidator = Validator<Record<string, unknown>, AnySchema>

export type ResolveValidatorInputFn<TValidator> = TValidator extends (
export type ResolveSearchValidatorInputFn<TValidator> = TValidator extends (
input: infer TSchemaInput,
) => any
? TSchemaInput extends SearchSchemaInput
? Omit<TSchemaInput, keyof SearchSchemaInput>
: ResolveValidatorOutputFn<TValidator>
: AnySchema

export type ResolveSearchValidatorInput<TValidator> =
TValidator extends AnyStandardSchemaValidator
? NonNullable<TValidator['~standard']['types']>['input']
: TValidator extends AnyValidatorAdapter
? TValidator['types']['input']
: TValidator extends AnyValidatorObj
? ResolveSearchValidatorInputFn<TValidator['parse']>
: ResolveSearchValidatorInputFn<TValidator>

export type ResolveValidatorInputFn<TValidator> = TValidator extends (
input: infer TInput,
) => any
? TInput
: undefined

export type ResolveValidatorInput<TValidator> =
TValidator extends AnyStandardSchemaValidator
? NonNullable<TValidator['~standard']['types']>['input']
Expand Down
22 changes: 11 additions & 11 deletions packages/start/src/client/createMiddleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ export type AnyMiddleware = MiddlewareTypes<any, any, any, any, any, any>
export interface MiddlewareTypes<
TId,
TMiddlewares,
TValidator extends AnyValidator,
TValidator,
TServerContext,
TClientContext,
TClientAfterContext,
Expand All @@ -266,12 +266,12 @@ export interface MiddlewareTypes<
export interface MiddlewareValidator<
TId,
TMiddlewares,
TValidator extends AnyValidator,
TValidator,
TServerContext,
TClientContext,
TClientAfterContext,
> {
validator: <TNewValidator extends AnyValidator>(
validator: <TNewValidator>(
input: TNewValidator,
) => MiddlewareAfterMiddleware<
TId,
Expand All @@ -286,7 +286,7 @@ export interface MiddlewareValidator<
export interface MiddlewareClientAfter<
TId,
TMiddlewares,
TValidator extends AnyValidator,
TValidator,
TServerContext,
TClientContext,
TClientAfterContext,
Expand All @@ -312,7 +312,7 @@ export interface MiddlewareClientAfter<
export interface MiddlewareAfterServer<
TId,
TMiddlewares,
TValidator extends AnyValidator,
TValidator,
TServerContext,
TClientContext,
TClientAfterContext,
Expand All @@ -336,7 +336,7 @@ export interface MiddlewareAfterServer<
export interface MiddlewareServer<
TId,
TMiddlewares,
TValidator extends AnyValidator,
TValidator,
TServerContext,
TClientContext,
TClientAfterContext,
Expand All @@ -362,7 +362,7 @@ export interface MiddlewareServer<
export interface MiddlewareAfterClient<
TId,
TMiddlewares,
TValidator extends AnyValidator,
TValidator,
TServerContext,
TClientContext,
TClientAfterContext,
Expand All @@ -386,7 +386,7 @@ export interface MiddlewareAfterClient<
export interface MiddlewareClient<
TId,
TMiddlewares,
TValidator extends AnyValidator,
TValidator,
TServerContext,
TClientContext,
TClientAfterContext,
Expand All @@ -411,7 +411,7 @@ export interface MiddlewareClient<
export interface MiddlewareAfterMiddleware<
TId,
TMiddlewares,
TValidator extends AnyValidator,
TValidator,
TServerContext,
TClientContext,
TClientAfterContext,
Expand Down Expand Up @@ -451,7 +451,7 @@ export interface MiddlewareAfterMiddleware<
export interface Middleware<
TId,
TMiddlewares,
TValidator extends AnyValidator,
TValidator,
TServerContext,
TClientContext,
TClientAfterContext,
Expand All @@ -478,7 +478,7 @@ export interface Middleware<
export function createMiddleware<
const TId,
const TMiddlewares,
TValidator extends AnyValidator = undefined,
TValidator = undefined,
TServerContext = undefined,
TClientContext = undefined,
TClientAfterContext = undefined,
Expand Down
37 changes: 21 additions & 16 deletions packages/start/src/client/tests/createServerFn.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ test('createServerFn without middleware', () => {
})

test('createServerFn with validator', () => {
createServerFn({ method: 'GET' })
.validator(() => ({
a: 'a',
const fn = createServerFn({ method: 'GET' })
.validator((input: { input: string }) => ({
a: input.input,
}))
.handler((options) => {
expectTypeOf(options).toEqualTypeOf<{
Expand All @@ -26,6 +26,11 @@ test('createServerFn with validator', () => {
}
}>()
})

expectTypeOf(fn).parameter(0).toEqualTypeOf<{
data: { input: string }
headers?: HeadersInit
}>()
})

test('createServerFn with middleware and context', () => {
Expand Down Expand Up @@ -75,16 +80,16 @@ test('createServerFn with middleware and context', () => {

test('createServerFn with middleware and validator', () => {
const middleware1 = createMiddleware().validator(
() =>
(input: { readonly inputA: 'inputA' }) =>
({
a: 'a',
outputA: 'outputA',
}) as const,
)

const middleware2 = createMiddleware().validator(
() =>
(input: { readonly inputB: 'inputB' }) =>
({
b: 'b',
outputB: 'outputB',
}) as const,
)

Expand All @@ -93,19 +98,19 @@ test('createServerFn with middleware and validator', () => {
const fn = createServerFn({ method: 'GET' })
.middleware([middleware3])
.validator(
() =>
(input: { readonly inputC: 'inputC' }) =>
({
c: 'c',
outputC: 'outputC',
}) as const,
)
.handler((options) => {
expectTypeOf(options).toEqualTypeOf<{
method: 'GET'
context: undefined
data: {
readonly a: 'a'
readonly b: 'b'
readonly c: 'c'
readonly outputA: 'outputA'
readonly outputB: 'outputB'
readonly outputC: 'outputC'
}
}>()

Expand All @@ -114,9 +119,9 @@ test('createServerFn with middleware and validator', () => {

expectTypeOf(fn).parameter(0).toEqualTypeOf<{
data: {
readonly a: 'a'
readonly b: 'b'
readonly c: 'c'
readonly inputA: 'inputA'
readonly inputB: 'inputB'
readonly inputC: 'inputC'
}
headers?: HeadersInit
}>()
Expand All @@ -138,7 +143,7 @@ test('createServerFn where validator is a primitive', () => {

test('createServerFn where validator is optional if object is optional', () => {
const fn = createServerFn({ method: 'GET' })
.validator(() => 'c' as 'c' | undefined)
.validator((input: 'c' | undefined) => input)
.handler((options) => {
expectTypeOf(options).toEqualTypeOf<{
method: 'GET'
Expand Down

0 comments on commit 7f8199c

Please sign in to comment.