@tanstack/form-core 0.13.6 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/FieldApi.cjs +1 -11
- package/dist/cjs/FieldApi.cjs.map +1 -1
- package/dist/cjs/FieldApi.d.cts +2 -3
- package/dist/cjs/FormApi.cjs +11 -9
- package/dist/cjs/FormApi.cjs.map +1 -1
- package/dist/cjs/FormApi.d.cts +3 -2
- package/dist/cjs/index.d.cts +1 -0
- package/dist/cjs/util-types.d.cts +29 -0
- package/dist/cjs/utils.cjs.map +1 -1
- package/dist/cjs/utils.d.cts +0 -19
- package/dist/esm/FieldApi.d.ts +2 -3
- package/dist/esm/FieldApi.js +1 -11
- package/dist/esm/FieldApi.js.map +1 -1
- package/dist/esm/FormApi.d.ts +3 -2
- package/dist/esm/FormApi.js +11 -9
- package/dist/esm/FormApi.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/util-types.d.ts +29 -0
- package/dist/esm/utils.d.ts +0 -19
- package/dist/esm/utils.js.map +1 -1
- package/package.json +1 -1
- package/src/FieldApi.ts +5 -34
- package/src/FormApi.ts +23 -22
- package/src/index.ts +1 -0
- package/src/tests/FieldApi.spec.ts +5 -25
- package/src/tests/FieldApi.test-d.ts +1 -1
- package/src/tests/FormApi.spec.ts +4 -4
- package/src/tests/mutateMergeDeep.spec.ts +1 -1
- package/src/tests/util-types.test-d.ts +106 -0
- package/src/tests/utils.spec.ts +8 -8
- package/src/util-types.ts +99 -0
- package/src/utils.ts +1 -73
package/src/FormApi.ts
CHANGED
|
@@ -8,7 +8,8 @@ import {
|
|
|
8
8
|
isNonEmptyArray,
|
|
9
9
|
setBy,
|
|
10
10
|
} from './utils'
|
|
11
|
-
import type {
|
|
11
|
+
import type { Updater } from './utils'
|
|
12
|
+
import type { DeepKeys, DeepValue } from './util-types'
|
|
12
13
|
import type { FieldApi, FieldMeta } from './FieldApi'
|
|
13
14
|
import type {
|
|
14
15
|
ValidationCause,
|
|
@@ -104,15 +105,12 @@ export type FieldInfo<
|
|
|
104
105
|
TFormData,
|
|
105
106
|
TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,
|
|
106
107
|
> = {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
TFormValidator
|
|
114
|
-
>
|
|
115
|
-
>
|
|
108
|
+
instance: FieldApi<
|
|
109
|
+
TFormData,
|
|
110
|
+
any,
|
|
111
|
+
Validator<unknown, unknown> | undefined,
|
|
112
|
+
TFormValidator
|
|
113
|
+
> | null
|
|
116
114
|
validationMetaMap: Record<ValidationErrorMapKeys, ValidationMeta | undefined>
|
|
117
115
|
}
|
|
118
116
|
|
|
@@ -314,7 +312,9 @@ export class FormApi<
|
|
|
314
312
|
Object.assign(
|
|
315
313
|
{},
|
|
316
314
|
this.state as any,
|
|
315
|
+
|
|
317
316
|
shouldUpdateState ? options.defaultState : {},
|
|
317
|
+
|
|
318
318
|
shouldUpdateValues
|
|
319
319
|
? {
|
|
320
320
|
values: options.defaultValues,
|
|
@@ -340,17 +340,17 @@ export class FormApi<
|
|
|
340
340
|
void (
|
|
341
341
|
Object.values(this.fieldInfo) as FieldInfo<any, TFormValidator>[]
|
|
342
342
|
).forEach((field) => {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
)
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
}
|
|
353
|
-
}
|
|
343
|
+
if (!field.instance) return
|
|
344
|
+
const fieldInstance = field.instance
|
|
345
|
+
// Validate the field
|
|
346
|
+
fieldValidationPromises.push(
|
|
347
|
+
Promise.resolve().then(() => fieldInstance.validate(cause)),
|
|
348
|
+
)
|
|
349
|
+
// If any fields are not touched
|
|
350
|
+
if (!field.instance.state.meta.isTouched) {
|
|
351
|
+
// Mark them as touched
|
|
352
|
+
field.instance.setMeta((prev) => ({ ...prev, isTouched: true }))
|
|
353
|
+
}
|
|
354
354
|
})
|
|
355
355
|
})
|
|
356
356
|
|
|
@@ -587,7 +587,7 @@ export class FormApi<
|
|
|
587
587
|
): FieldInfo<TFormData, TFormValidator> => {
|
|
588
588
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
589
589
|
return (this.fieldInfo[field] ||= {
|
|
590
|
-
|
|
590
|
+
instance: null,
|
|
591
591
|
validationMetaMap: {
|
|
592
592
|
onChange: undefined,
|
|
593
593
|
onBlur: undefined,
|
|
@@ -645,6 +645,7 @@ export class FormApi<
|
|
|
645
645
|
|
|
646
646
|
return newState
|
|
647
647
|
})
|
|
648
|
+
delete this.fieldInfo[field]
|
|
648
649
|
}
|
|
649
650
|
|
|
650
651
|
pushFieldValue = <TField extends DeepKeys<TFormData>>(
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { expect,
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
2
2
|
|
|
3
3
|
import { FormApi } from '../FormApi'
|
|
4
4
|
import { FieldApi } from '../FieldApi'
|
|
@@ -154,26 +154,6 @@ describe('field api', () => {
|
|
|
154
154
|
expect(field.getValue()).toStrictEqual(['two', 'one'])
|
|
155
155
|
})
|
|
156
156
|
|
|
157
|
-
it('should get a subfield properly', () => {
|
|
158
|
-
const form = new FormApi({
|
|
159
|
-
defaultValues: {
|
|
160
|
-
names: {
|
|
161
|
-
first: 'one',
|
|
162
|
-
second: 'two',
|
|
163
|
-
},
|
|
164
|
-
},
|
|
165
|
-
})
|
|
166
|
-
|
|
167
|
-
const field = new FieldApi({
|
|
168
|
-
form,
|
|
169
|
-
name: 'names',
|
|
170
|
-
})
|
|
171
|
-
|
|
172
|
-
const subfield = field.getSubField('first')
|
|
173
|
-
|
|
174
|
-
expect(subfield.getValue()).toBe('one')
|
|
175
|
-
})
|
|
176
|
-
|
|
177
157
|
it('should not throw errors when no meta info is stored on a field and a form re-renders', async () => {
|
|
178
158
|
const form = new FormApi({
|
|
179
159
|
defaultValues: {
|
|
@@ -602,7 +582,7 @@ describe('field api', () => {
|
|
|
602
582
|
|
|
603
583
|
const unmount = field.mount()
|
|
604
584
|
unmount()
|
|
605
|
-
expect(form.getFieldInfo(field.name).
|
|
585
|
+
expect(form.getFieldInfo(field.name).instance).toBeDefined()
|
|
606
586
|
expect(form.getFieldInfo(field.name)).toBeDefined()
|
|
607
587
|
})
|
|
608
588
|
|
|
@@ -619,13 +599,13 @@ describe('field api', () => {
|
|
|
619
599
|
})
|
|
620
600
|
|
|
621
601
|
const unmount = field.mount()
|
|
622
|
-
const callback =
|
|
602
|
+
const callback = vi.fn()
|
|
623
603
|
const subscription = form.store.subscribe(callback)
|
|
624
604
|
unmount()
|
|
625
605
|
const info = form.getFieldInfo(field.name)
|
|
626
606
|
subscription()
|
|
627
|
-
expect(info.
|
|
628
|
-
expect(Object.keys(info.
|
|
607
|
+
expect(info.instance).toBeNull()
|
|
608
|
+
expect(Object.keys(info.instance ?? {}).length).toBe(0)
|
|
629
609
|
|
|
630
610
|
// Check that form store has been updated
|
|
631
611
|
expect(callback).toHaveBeenCalledOnce()
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { expect } from 'vitest'
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
2
2
|
|
|
3
3
|
import { FormApi } from '../FormApi'
|
|
4
4
|
import { FieldApi } from '../FieldApi'
|
|
@@ -272,7 +272,7 @@ describe('form api', () => {
|
|
|
272
272
|
|
|
273
273
|
const fieldInArray = new FieldApi({
|
|
274
274
|
form,
|
|
275
|
-
name: `employees
|
|
275
|
+
name: `employees[0].firstName`,
|
|
276
276
|
defaultValue: 'Darcy',
|
|
277
277
|
})
|
|
278
278
|
fieldInArray.mount()
|
|
@@ -300,11 +300,11 @@ describe('form api', () => {
|
|
|
300
300
|
|
|
301
301
|
const fieldInArray = new FieldApi({
|
|
302
302
|
form,
|
|
303
|
-
name: `employees
|
|
303
|
+
name: `employees[0].firstName`,
|
|
304
304
|
defaultValue: 'Darcy',
|
|
305
305
|
})
|
|
306
306
|
fieldInArray.mount()
|
|
307
|
-
form.deleteField(`employees
|
|
307
|
+
form.deleteField(`employees[0].firstName`)
|
|
308
308
|
expect(field.state.value.length).toBe(1)
|
|
309
309
|
expect(Object.keys(field.state.value[0]!).length).toBe(0)
|
|
310
310
|
})
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { assertType } from 'vitest'
|
|
2
|
+
import type { DeepKeys, DeepValue } from '../util-types'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Properly recognizes that `0` is not an object and should not have subkeys
|
|
6
|
+
*/
|
|
7
|
+
type TupleSupport = DeepKeys<{ topUsers: [User, 0, User] }>
|
|
8
|
+
assertType<
|
|
9
|
+
| 'topUsers'
|
|
10
|
+
| 'topUsers[0]'
|
|
11
|
+
| 'topUsers[0].name'
|
|
12
|
+
| 'topUsers[0].id'
|
|
13
|
+
| 'topUsers[0].age'
|
|
14
|
+
| 'topUsers[1]'
|
|
15
|
+
| 'topUsers[2]'
|
|
16
|
+
| 'topUsers[2].name'
|
|
17
|
+
| 'topUsers[2].id'
|
|
18
|
+
| 'topUsers[2].age'
|
|
19
|
+
>(0 as never as TupleSupport)
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Properly recognizes that a normal number index won't cut it and should be `[number]` prefixed instead
|
|
23
|
+
*/
|
|
24
|
+
type ArraySupport = DeepKeys<{ users: User[] }>
|
|
25
|
+
assertType<
|
|
26
|
+
| 'users'
|
|
27
|
+
| `users[${number}].name`
|
|
28
|
+
| `users[${number}].id`
|
|
29
|
+
| `users[${number}].age`
|
|
30
|
+
>(0 as never as ArraySupport)
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Properly handles deep object nesting like so:
|
|
34
|
+
*/
|
|
35
|
+
type NestedSupport = DeepKeys<{ meta: { mainUser: User } }>
|
|
36
|
+
assertType<
|
|
37
|
+
| 'meta'
|
|
38
|
+
| 'meta.mainUser'
|
|
39
|
+
| 'meta.mainUser.name'
|
|
40
|
+
| 'meta.mainUser.id'
|
|
41
|
+
| 'meta.mainUser.age'
|
|
42
|
+
>(0 as never as NestedSupport)
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Properly handles `object` edgecase nesting like so:
|
|
46
|
+
*/
|
|
47
|
+
type ObjectNestedEdgecase = DeepKeys<{ meta: { mainUser: object } }>
|
|
48
|
+
assertType<'meta' | 'meta.mainUser' | `meta.mainUser.${string}`>(
|
|
49
|
+
0 as never as ObjectNestedEdgecase,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Properly handles `object` edgecase like so:
|
|
54
|
+
*/
|
|
55
|
+
type ObjectEdgecase = DeepKeys<object>
|
|
56
|
+
assertType<string>(0 as never as ObjectEdgecase)
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Properly handles `object` edgecase nesting like so:
|
|
60
|
+
*/
|
|
61
|
+
type UnknownNestedEdgecase = DeepKeys<{ meta: { mainUser: unknown } }>
|
|
62
|
+
assertType<'meta' | 'meta.mainUser' | `meta.mainUser.${string}`>(
|
|
63
|
+
0 as never as UnknownNestedEdgecase,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Properly handles `object` edgecase like so:
|
|
68
|
+
*/
|
|
69
|
+
type UnknownEdgecase = DeepKeys<unknown>
|
|
70
|
+
assertType<string>(0 as never as UnknownEdgecase)
|
|
71
|
+
|
|
72
|
+
type NestedKeysExample = DeepValue<
|
|
73
|
+
{ meta: { mainUser: User } },
|
|
74
|
+
'meta.mainUser.age'
|
|
75
|
+
>
|
|
76
|
+
assertType<number>(0 as never as NestedKeysExample)
|
|
77
|
+
|
|
78
|
+
type NestedArrayExample = DeepValue<{ users: User[] }, 'users[0].age'>
|
|
79
|
+
assertType<number>(0 as never as NestedArrayExample)
|
|
80
|
+
|
|
81
|
+
type NestedLooseArrayExample = DeepValue<{ users: User[] }, 'users[number].age'>
|
|
82
|
+
assertType<number>(0 as never as NestedLooseArrayExample)
|
|
83
|
+
|
|
84
|
+
type NestedTupleExample = DeepValue<
|
|
85
|
+
{ topUsers: [User, 0, User] },
|
|
86
|
+
'topUsers[0].age'
|
|
87
|
+
>
|
|
88
|
+
assertType<number>(0 as never as NestedTupleExample)
|
|
89
|
+
|
|
90
|
+
type NestedTupleItemExample = DeepValue<
|
|
91
|
+
{ topUsers: [User, 0, User] },
|
|
92
|
+
'topUsers[1]'
|
|
93
|
+
>
|
|
94
|
+
assertType<0>(0 as never as NestedTupleItemExample)
|
|
95
|
+
|
|
96
|
+
type ArrayExample = DeepValue<[1, 2, 3], '[1]'>
|
|
97
|
+
assertType<2>(0 as never as ArrayExample)
|
|
98
|
+
|
|
99
|
+
type NonNestedObjExample = DeepValue<{ a: 1 }, 'a'>
|
|
100
|
+
assertType<1>(0 as never as NonNestedObjExample)
|
|
101
|
+
|
|
102
|
+
interface User {
|
|
103
|
+
name: string
|
|
104
|
+
id: string
|
|
105
|
+
age: number
|
|
106
|
+
}
|
package/src/tests/utils.spec.ts
CHANGED
|
@@ -19,8 +19,8 @@ describe('getBy', () => {
|
|
|
19
19
|
})
|
|
20
20
|
|
|
21
21
|
it('should get array subfields by path', () => {
|
|
22
|
-
expect(getBy(structure, 'kids
|
|
23
|
-
expect(getBy(structure, 'kids
|
|
22
|
+
expect(getBy(structure, 'kids[0].name')).toBe(structure.kids[0]!.name)
|
|
23
|
+
expect(getBy(structure, 'kids[0].age')).toBe(structure.kids[0]!.age)
|
|
24
24
|
})
|
|
25
25
|
})
|
|
26
26
|
|
|
@@ -42,10 +42,10 @@ describe('setBy', () => {
|
|
|
42
42
|
})
|
|
43
43
|
|
|
44
44
|
it('should set array subfields by path', () => {
|
|
45
|
-
expect(setBy(structure, 'kids
|
|
45
|
+
expect(setBy(structure, 'kids[0].name', 'Taylor').kids[0].name).toBe(
|
|
46
46
|
'Taylor',
|
|
47
47
|
)
|
|
48
|
-
expect(setBy(structure, 'kids
|
|
48
|
+
expect(setBy(structure, 'kids[0].age', 20).kids[0].age).toBe(20)
|
|
49
49
|
})
|
|
50
50
|
})
|
|
51
51
|
|
|
@@ -67,14 +67,14 @@ describe('deleteBy', () => {
|
|
|
67
67
|
})
|
|
68
68
|
|
|
69
69
|
it('should delete array subfields by path', () => {
|
|
70
|
-
expect(deleteBy(structure, 'kids
|
|
71
|
-
expect(deleteBy(structure, 'kids
|
|
70
|
+
expect(deleteBy(structure, 'kids[0].name').kids[0].name).not.toBeDefined()
|
|
71
|
+
expect(deleteBy(structure, 'kids[0].age').kids[0].age).not.toBeDefined()
|
|
72
72
|
})
|
|
73
73
|
|
|
74
74
|
it('should delete non-existent paths like a noop', () => {
|
|
75
75
|
expect(deleteBy(structure, 'nonexistent')).toEqual(structure)
|
|
76
76
|
expect(deleteBy(structure, 'nonexistent.nonexistent')).toEqual(structure)
|
|
77
|
-
expect(deleteBy(structure, 'kids
|
|
78
|
-
expect(deleteBy(structure, 'nonexistent
|
|
77
|
+
expect(deleteBy(structure, 'kids[3].name')).toEqual(structure)
|
|
78
|
+
expect(deleteBy(structure, 'nonexistent[3].nonexistent')).toEqual(structure)
|
|
79
79
|
})
|
|
80
80
|
})
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
export type RequiredByKey<T, K extends keyof T> = Omit<T, K> &
|
|
2
|
+
Required<Pick<T, K>>
|
|
3
|
+
|
|
4
|
+
type Narrowable = string | number | bigint | boolean
|
|
5
|
+
|
|
6
|
+
type NarrowRaw<A> =
|
|
7
|
+
| (A extends [] ? [] : never)
|
|
8
|
+
| (A extends Narrowable ? A : never)
|
|
9
|
+
| {
|
|
10
|
+
[K in keyof A]: A[K] extends Function ? A[K] : NarrowRaw<A[K]>
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type Narrow<A> = Try<A, [], NarrowRaw<A>>
|
|
14
|
+
|
|
15
|
+
type Try<A1, A2, Catch = never> = A1 extends A2 ? A1 : Catch
|
|
16
|
+
|
|
17
|
+
// Hack to get TypeScript to show simplified types in error messages
|
|
18
|
+
export type Pretty<T> = { [K in keyof T]: T[K] } & {}
|
|
19
|
+
|
|
20
|
+
type ComputeRange<
|
|
21
|
+
N extends number,
|
|
22
|
+
Result extends Array<unknown> = [],
|
|
23
|
+
> = Result['length'] extends N
|
|
24
|
+
? Result
|
|
25
|
+
: ComputeRange<N, [...Result, Result['length']]>
|
|
26
|
+
type Index40 = ComputeRange<40>[number]
|
|
27
|
+
|
|
28
|
+
// Is this type a tuple?
|
|
29
|
+
type IsTuple<T> = T extends readonly any[] & { length: infer Length }
|
|
30
|
+
? Length extends Index40
|
|
31
|
+
? T
|
|
32
|
+
: never
|
|
33
|
+
: never
|
|
34
|
+
|
|
35
|
+
// If this type is a tuple, what indices are allowed?
|
|
36
|
+
type AllowedIndexes<
|
|
37
|
+
Tuple extends ReadonlyArray<any>,
|
|
38
|
+
Keys extends number = never,
|
|
39
|
+
> = Tuple extends readonly []
|
|
40
|
+
? Keys
|
|
41
|
+
: Tuple extends readonly [infer _, ...infer Tail]
|
|
42
|
+
? AllowedIndexes<Tail, Keys | Tail['length']>
|
|
43
|
+
: Keys
|
|
44
|
+
|
|
45
|
+
type PrefixArrayAccessor<T extends any[], TDepth extends any[]> = {
|
|
46
|
+
[K in keyof T]: `[${number}]${DeepKeys<T[K], TDepth>}`
|
|
47
|
+
}[number]
|
|
48
|
+
|
|
49
|
+
type PrefixTupleAccessor<
|
|
50
|
+
T extends any[],
|
|
51
|
+
TIndex extends number,
|
|
52
|
+
TDepth extends any[],
|
|
53
|
+
> = {
|
|
54
|
+
[K in TIndex]: `[${K}]` | `[${K}]${DeepKeys<T[K], TDepth>}`
|
|
55
|
+
}[TIndex]
|
|
56
|
+
|
|
57
|
+
type PrefixObjectAccessor<T extends object, TDepth extends any[]> = {
|
|
58
|
+
[K in keyof T]: K extends string | number
|
|
59
|
+
?
|
|
60
|
+
| PrefixFromDepth<K, TDepth>
|
|
61
|
+
| `${PrefixFromDepth<K, TDepth>}${DeepKeys<T[K], [TDepth]>}`
|
|
62
|
+
: never
|
|
63
|
+
}[keyof T]
|
|
64
|
+
|
|
65
|
+
export type DeepKeys<T, TDepth extends any[] = []> = TDepth['length'] extends 5
|
|
66
|
+
? never
|
|
67
|
+
: unknown extends T
|
|
68
|
+
? PrefixFromDepth<string, TDepth>
|
|
69
|
+
: object extends T
|
|
70
|
+
? PrefixFromDepth<string, TDepth>
|
|
71
|
+
: T extends readonly any[] & IsTuple<T>
|
|
72
|
+
? PrefixTupleAccessor<T, AllowedIndexes<T>, TDepth>
|
|
73
|
+
: T extends any[]
|
|
74
|
+
? PrefixArrayAccessor<T, [...TDepth, any]>
|
|
75
|
+
: T extends Date
|
|
76
|
+
? never
|
|
77
|
+
: T extends object
|
|
78
|
+
? PrefixObjectAccessor<T, TDepth>
|
|
79
|
+
: never
|
|
80
|
+
|
|
81
|
+
type PrefixFromDepth<
|
|
82
|
+
T extends string | number,
|
|
83
|
+
TDepth extends any[],
|
|
84
|
+
> = TDepth['length'] extends 0 ? T : `.${T}`
|
|
85
|
+
|
|
86
|
+
export type DeepValue<TValue, TAccessor> = TValue extends Record<
|
|
87
|
+
string | number,
|
|
88
|
+
any
|
|
89
|
+
>
|
|
90
|
+
? TAccessor extends `${infer TBefore}[${infer TBrackets}].${infer TAfter}`
|
|
91
|
+
? DeepValue<TValue[TBefore][TBrackets], TAfter>
|
|
92
|
+
: TAccessor extends `[${infer TBrackets}]`
|
|
93
|
+
? DeepValue<TValue, TBrackets>
|
|
94
|
+
: TAccessor extends `${infer TBefore}[${infer TBrackets}]`
|
|
95
|
+
? DeepValue<TValue[TBefore], TBrackets>
|
|
96
|
+
: TAccessor extends `${infer TBefore}.${infer TAfter}`
|
|
97
|
+
? DeepValue<TValue[TBefore], TAfter>
|
|
98
|
+
: TValue[TAccessor & string]
|
|
99
|
+
: never
|
package/src/utils.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ValidationCause
|
|
1
|
+
import type { ValidationCause } from './types'
|
|
2
2
|
import type { FormValidators } from './FormApi'
|
|
3
3
|
import type { FieldValidators } from './FieldApi'
|
|
4
4
|
|
|
@@ -267,75 +267,3 @@ export function getSyncValidatorArray<T>(
|
|
|
267
267
|
return [changeValidator, serverValidator] as never
|
|
268
268
|
}
|
|
269
269
|
}
|
|
270
|
-
|
|
271
|
-
export type RequiredByKey<T, K extends keyof T> = Omit<T, K> &
|
|
272
|
-
Required<Pick<T, K>>
|
|
273
|
-
|
|
274
|
-
type ComputeRange<
|
|
275
|
-
N extends number,
|
|
276
|
-
Result extends Array<unknown> = [],
|
|
277
|
-
> = Result['length'] extends N
|
|
278
|
-
? Result
|
|
279
|
-
: ComputeRange<N, [...Result, Result['length']]>
|
|
280
|
-
type Index40 = ComputeRange<40>[number]
|
|
281
|
-
|
|
282
|
-
// Is this type a tuple?
|
|
283
|
-
type IsTuple<T> = T extends readonly any[] & { length: infer Length }
|
|
284
|
-
? Length extends Index40
|
|
285
|
-
? T
|
|
286
|
-
: never
|
|
287
|
-
: never
|
|
288
|
-
|
|
289
|
-
// If this type is a tuple, what indices are allowed?
|
|
290
|
-
type AllowedIndexes<
|
|
291
|
-
Tuple extends ReadonlyArray<any>,
|
|
292
|
-
Keys extends number = never,
|
|
293
|
-
> = Tuple extends readonly []
|
|
294
|
-
? Keys
|
|
295
|
-
: Tuple extends readonly [infer _, ...infer Tail]
|
|
296
|
-
? AllowedIndexes<Tail, Keys | Tail['length']>
|
|
297
|
-
: Keys
|
|
298
|
-
|
|
299
|
-
export type DeepKeys<T, TDepth extends any[] = []> = TDepth['length'] extends 5
|
|
300
|
-
? never
|
|
301
|
-
: unknown extends T
|
|
302
|
-
? string
|
|
303
|
-
: T extends readonly any[] & IsTuple<T>
|
|
304
|
-
? AllowedIndexes<T> | DeepKeysPrefix<T, AllowedIndexes<T>, TDepth>
|
|
305
|
-
: T extends any[]
|
|
306
|
-
? DeepKeysPrefix<T, number, TDepth>
|
|
307
|
-
: T extends Date
|
|
308
|
-
? never
|
|
309
|
-
: T extends object
|
|
310
|
-
? (keyof T & string) | DeepKeysPrefix<T, keyof T, TDepth>
|
|
311
|
-
: never
|
|
312
|
-
|
|
313
|
-
type DeepKeysPrefix<
|
|
314
|
-
T,
|
|
315
|
-
TPrefix,
|
|
316
|
-
TDepth extends any[],
|
|
317
|
-
> = TPrefix extends keyof T & (number | string)
|
|
318
|
-
? `${TPrefix}.${DeepKeys<T[TPrefix], [...TDepth, any]> & string}`
|
|
319
|
-
: never
|
|
320
|
-
|
|
321
|
-
export type DeepValue<T, TProp> = T extends Record<string | number, any>
|
|
322
|
-
? TProp extends `${infer TBranch}.${infer TDeepProp}`
|
|
323
|
-
? DeepValue<T[TBranch], TDeepProp>
|
|
324
|
-
: T[TProp & string]
|
|
325
|
-
: never
|
|
326
|
-
|
|
327
|
-
type Narrowable = string | number | bigint | boolean
|
|
328
|
-
|
|
329
|
-
type NarrowRaw<A> =
|
|
330
|
-
| (A extends [] ? [] : never)
|
|
331
|
-
| (A extends Narrowable ? A : never)
|
|
332
|
-
| {
|
|
333
|
-
[K in keyof A]: A[K] extends Function ? A[K] : NarrowRaw<A[K]>
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
export type Narrow<A> = Try<A, [], NarrowRaw<A>>
|
|
337
|
-
|
|
338
|
-
type Try<A1, A2, Catch = never> = A1 extends A2 ? A1 : Catch
|
|
339
|
-
|
|
340
|
-
// Hack to get TypeScript to show simplified types in error messages
|
|
341
|
-
export type Pretty<T> = { [K in keyof T]: T[K] } & {}
|