Skip to content

Commit c1cc8c0

Browse files
committed
Fixed FormPathLeaves inference for arrays.
1 parent 707a228 commit c1cc8c0

File tree

2 files changed

+37
-14
lines changed

2 files changed

+37
-14
lines changed

src/lib/stringPath.ts

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -122,14 +122,25 @@ type StringPath<
122122
never,
123123
T[K]
124124
>
125-
: If<
126-
Options,
127-
'filter',
128-
'leaves' | 'all',
129-
Concat<Options['path'], `${K}[${number}]`>,
130-
never,
131-
U
132-
>)
125+
: NonNullable<U> extends object
126+
? IsAny<T[K]> extends true
127+
? Concat<Options['path'], `${K}[${number}]`>
128+
: If<
129+
Options,
130+
'filter',
131+
'all',
132+
Concat<Options['path'], `${K}[${number}]`>,
133+
never,
134+
U
135+
>
136+
: If<
137+
Options,
138+
'filter',
139+
'leaves' | 'all',
140+
Concat<Options['path'], `${K}[${number}]`>,
141+
never,
142+
U
143+
>)
133144
| (NonNullable<U> extends object
134145
? StringPath<
135146
NonNullable<U>,

src/tests/legacy/paths.test-d.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -327,11 +327,7 @@ test('FormPath with type narrowing, arrays', () => {
327327
test('FormPath with type narrowing, union', () => {
328328
type NameArrays = FormPath<Obj, string | number>;
329329

330-
const t1: NameArrays = 'name';
331-
const t2: NameArrays = 'points';
332-
const t3: NameArrays = 'tags[3].name';
333-
const t4: NameArrays = 'names[3]';
334-
const t5: NameArrays = 'tags[0].parents[5]';
330+
const ok: NameArrays[] = ['name', 'points', 'tags[3].name', 'names[3]', 'tags[0].parents[5]'];
335331

336332
// @ts-expect-error incorrect path
337333
const i1: NameArrays = 'tags';
@@ -371,7 +367,6 @@ test('FormPath with any type', () => {
371367

372368
// @ts-expect-error Invalid path
373369
const f1: FP = 'nope';
374-
// @ts-expect-error Invalid path
375370
const f2: FPA = 'age[3]';
376371
});
377372

@@ -389,6 +384,23 @@ test('Schemas with built-in objects', () => {
389384
const tf: FPL = 'name';
390385
});
391386

387+
test('Schema with nested arrays', () => {
388+
const reportSchema = z.object({
389+
reportDate: z.date(),
390+
images: z.instanceof(File, { message: 'Please upload a file.' }).array()
391+
});
392+
393+
const schema = z.object({
394+
reports: z.array(reportSchema).min(1, 'At least one report must be submitted')
395+
});
396+
397+
type FPL = FormPathLeaves<Infer<typeof schema>>;
398+
399+
const ok: FPL[] = ['reports[3].reportDate', 'reports[3].images[2]'];
400+
// @ts-expect-error Invalid type
401+
const no: FPL = 'reports[3]';
402+
});
403+
392404
///////////////////////////////////////////////////
393405

394406
// Recursive schema test

0 commit comments

Comments
 (0)