Skip to content

Commit 20aed41

Browse files
committed
fix(types): preserve legacy request handler compatibility
1 parent d1d478c commit 20aed41

2 files changed

Lines changed: 31 additions & 24 deletions

File tree

storage/framework/core/actions/tests/action-typing.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,13 @@ function _checkBare(r: RequestInstance): unknown {
122122
}
123123
void _checkBare
124124

125+
// A request narrowed by action validations remains assignable to legacy
126+
// handlers that intentionally accept the broad RequestInstance shape.
127+
function _checkLegacyRequestCompatibility(r: RequestInstance<{ email: string }>): unknown {
128+
return _checkBare(r)
129+
}
130+
void _checkLegacyRequestCompatibility
131+
125132
// ─── End-to-end smoke (#1851 Phase 4) ────────────────────────────
126133
//
127134
// Importing the smoke fixture forces it through TS in this test

storage/framework/core/types/src/request.ts

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -141,12 +141,12 @@ export interface Collection<T> {
141141
* Safe validated data wrapper (Laravel-style)
142142
*/
143143
export interface SafeData<T extends Record<string, any> = Record<string, any>> {
144-
only: <K extends keyof T>(keys: K[]) => Pick<T, K>
145-
except: <K extends keyof T>(keys: K[]) => Omit<T, K>
146-
merge: <U extends Record<string, unknown>>(data: U) => T & U
147-
all: () => T
148-
has: (key: keyof T) => boolean
149-
get: <K extends keyof T>(key: K) => T[K]
144+
only<K extends keyof T>(keys: K[]): Pick<T, K>
145+
except<K extends keyof T>(keys: K[]): Omit<T, K>
146+
merge<U extends Record<string, unknown>>(data: U): T & U
147+
all(): T
148+
has(key: keyof T): boolean
149+
get<K extends keyof T>(key: K): T[K]
150150
}
151151

152152
/**
@@ -292,13 +292,13 @@ export interface RequestInstance<
292292
* Get only specified keys — returns a precisely picked type
293293
* @example request.only(['title', 'views']) // { title: string, views: number }
294294
*/
295-
only: <K extends keyof TFields & string>(keys: K[]) => Pick<TFields, K>
295+
only<K extends keyof TFields & string>(keys: K[]): Pick<TFields, K>
296296

297297
/**
298298
* Get all except specified keys — returns a precisely omitted type
299299
* @example request.except(['id', 'created_at']) // omits those fields
300300
*/
301-
except: <K extends keyof TFields & string>(keys: K[]) => Omit<TFields, K>
301+
except<K extends keyof TFields & string>(keys: K[]): Omit<TFields, K>
302302

303303
/**
304304
* Check if input has a key (or all keys if array) — keys narrowed to model fields
@@ -328,7 +328,7 @@ export interface RequestInstance<
328328
/**
329329
* Merge additional data into input — accepts partial model fields
330330
*/
331-
merge: (data: Partial<TFields>) => void
331+
merge(data: Partial<TFields>): void
332332

333333
/**
334334
* Get all input keys — returns model field names when model-aware
@@ -343,49 +343,49 @@ export interface RequestInstance<
343343
* Get string input
344344
* @example request.string('title')
345345
*/
346-
string: (key: keyof TFields & string, defaultValue?: string) => string
346+
string(key: keyof TFields & string, defaultValue?: string): string
347347

348348
/**
349349
* Get integer input
350350
* @example request.integer('views', 0)
351351
*/
352-
integer: (key: keyof TFields & string, defaultValue?: number) => number
352+
integer(key: keyof TFields & string, defaultValue?: number): number
353353

354354
/**
355355
* Get float input
356356
* @example request.float('price', 0.0)
357357
*/
358-
float: (key: keyof TFields & string, defaultValue?: number) => number
358+
float(key: keyof TFields & string, defaultValue?: number): number
359359

360360
/**
361361
* Get boolean input
362362
* @example request.boolean('is_active', false)
363363
*/
364-
boolean: (key: keyof TFields & string, defaultValue?: boolean) => boolean
364+
boolean(key: keyof TFields & string, defaultValue?: boolean): boolean
365365

366366
/**
367367
* Get input as array
368368
* @example request.array('tags')
369369
*/
370-
array: <T = unknown>(key: keyof TFields & string) => T[]
370+
array<T = unknown>(key: keyof TFields & string): T[]
371371

372372
/**
373373
* Parse date input
374374
* @example request.date('published_at')
375375
*/
376-
date: (key: keyof TFields & string, format?: string) => Date | null
376+
date(key: keyof TFields & string, format?: string): Date | null
377377

378378
/**
379379
* Parse enum input
380380
* @example request.enum('status', StatusEnum)
381381
*/
382-
enum: <T extends Record<string, string | number>>(key: keyof TFields & string, enumType: T) => T[keyof T] | null
382+
enum<T extends Record<string, string | number>>(key: keyof TFields & string, enumType: T): T[keyof T] | null
383383

384384
/**
385385
* Get input as collection
386386
* @example request.collect('items')
387387
*/
388-
collect: <T = unknown>(key: keyof TFields & string) => Collection<T>
388+
collect<T = unknown>(key: keyof TFields & string): Collection<T>
389389

390390
// ==========================================================================
391391
// Validation Methods — returns typed model fields when model-aware
@@ -421,18 +421,18 @@ export interface RequestInstance<
421421
* Execute callback when input has a value
422422
* @example request.whenHas('title', (value) => console.log(value))
423423
*/
424-
whenHas: <T>(key: keyof TFields & string, callback: (value: T) => void, defaultCallback?: () => void) => void
424+
whenHas<T>(key: keyof TFields & string, callback: (value: T) => void, defaultCallback?: () => void): void
425425

426426
/**
427427
* Execute callback when input is filled
428428
* @example request.whenFilled('title', (value) => console.log(value))
429429
*/
430-
whenFilled: <T>(key: keyof TFields & string, callback: (value: T) => void, defaultCallback?: () => void) => void
430+
whenFilled<T>(key: keyof TFields & string, callback: (value: T) => void, defaultCallback?: () => void): void
431431

432432
/**
433433
* Check if input matches a value
434434
*/
435-
isValue: (key: keyof TFields & string, value: unknown) => boolean
435+
isValue(key: keyof TFields & string, value: unknown): boolean
436436

437437
// ==========================================================================
438438
// File Methods — not narrowed to model fields (files are independent)
@@ -510,22 +510,22 @@ export interface RequestInstance<
510510
/**
511511
* Get old input (for form repopulation)
512512
*/
513-
old: <T = unknown>(key: keyof TFields & string, defaultValue?: T) => T
513+
old<T = unknown>(key: keyof TFields & string, defaultValue?: T): T
514514

515515
/**
516516
* Flash input to session for form repopulation
517517
*/
518-
flashInput: (keys?: (keyof TFields & string)[]) => void
518+
flashInput(keys?: (keyof TFields & string)[]): void
519519

520520
/**
521521
* Flash only specific keys
522522
*/
523-
flashInputOnly: (keys: (keyof TFields & string)[]) => void
523+
flashInputOnly(keys: (keyof TFields & string)[]): void
524524

525525
/**
526526
* Flash except specific keys
527527
*/
528-
flashInputExcept: (keys: (keyof TFields & string)[]) => void
528+
flashInputExcept(keys: (keyof TFields & string)[]): void
529529

530530
// ==========================================================================
531531
// Utility Methods

0 commit comments

Comments
 (0)