Skip to content

Commit 638a391

Browse files
fix: remove _TData abstraction (#465)
* fix: remove _TData abstraction * tests: fix
1 parent 9e5fef4 commit 638a391

File tree

8 files changed

+80
-152
lines changed

8 files changed

+80
-152
lines changed

packages/form-core/src/FieldApi.ts

Lines changed: 34 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,21 @@ import { Store } from '@tanstack/store'
44

55
export type ValidationCause = 'change' | 'blur' | 'submit' | 'mount'
66

7-
type ValidateFn<TData, TParentData, TName extends DeepKeys<TParentData>> = (
7+
type ValidateFn<TParentData, TName extends DeepKeys<TParentData>, TData> = (
88
value: TData,
9-
fieldApi: FieldApi<TData, TParentData, TName>,
9+
fieldApi: FieldApi<TParentData, TName>,
1010
) => ValidationError
1111

1212
type ValidateAsyncFn<
13-
TData,
1413
TParentData,
1514
TName extends DeepKeys<TParentData>,
15+
TData,
1616
> = (
1717
value: TData,
18-
fieldApi: FieldApi<TData, TParentData, TName>,
18+
fieldApi: FieldApi<TParentData, TName>,
1919
) => ValidationError | Promise<ValidationError>
2020

2121
export interface FieldOptions<
22-
TData,
2322
TParentData,
2423
/**
2524
* This allows us to restrict the name to only be a valid field name while
@@ -29,41 +28,29 @@ export interface FieldOptions<
2928
/**
3029
* If TData is unknown, we can use the TName generic to determine the type
3130
*/
32-
TResolvedData = unknown extends TData ? DeepValue<TParentData, TName> : TData,
31+
TData = DeepValue<TParentData, TName>,
3332
> {
3433
name: DeepKeys<TParentData>
35-
index?: TResolvedData extends any[] ? number : never
36-
defaultValue?: TResolvedData
34+
index?: TData extends any[] ? number : never
35+
defaultValue?: TData
3736
asyncDebounceMs?: number
3837
asyncAlways?: boolean
39-
onMount?: (formApi: FieldApi<TResolvedData, TParentData, TName>) => void
40-
onChange?: ValidateFn<TResolvedData, TParentData, TName>
41-
onChangeAsync?: ValidateAsyncFn<TResolvedData, TParentData, TName>
38+
onMount?: (formApi: FieldApi<TParentData, TName>) => void
39+
onChange?: ValidateFn<TParentData, TName, TData>
40+
onChangeAsync?: ValidateAsyncFn<TParentData, TName, TData>
4241
onChangeAsyncDebounceMs?: number
43-
onBlur?: ValidateFn<TResolvedData, TParentData, TName>
44-
onBlurAsync?: ValidateAsyncFn<TResolvedData, TParentData, TName>
42+
onBlur?: ValidateFn<TParentData, TName, TData>
43+
onBlurAsync?: ValidateAsyncFn<TParentData, TName, TData>
4544
onBlurAsyncDebounceMs?: number
46-
onSubmitAsync?: ValidateAsyncFn<TResolvedData, TParentData, TName>
45+
onSubmitAsync?: ValidateAsyncFn<TParentData, TName, TData>
4746
defaultMeta?: Partial<FieldMeta>
4847
}
4948

5049
export interface FieldApiOptions<
51-
TData,
5250
TParentData,
53-
/**
54-
* This allows us to restrict the name to only be a valid field name while
55-
* also assigning it to a generic
56-
*/
5751
TName extends DeepKeys<TParentData>,
58-
/**
59-
* If TData is unknown, we can use the TName generic to determine the type
60-
*/
61-
TResolvedData extends ResolveData<TData, TParentData, TName> = ResolveData<
62-
TData,
63-
TParentData,
64-
TName
65-
>,
66-
> extends FieldOptions<TData, TParentData, TName, TResolvedData> {
52+
TData = DeepValue<TParentData, TName>,
53+
> extends FieldOptions<TParentData, TName, TData> {
6754
form: FormApi<TParentData>
6855
}
6956

@@ -82,34 +69,25 @@ export type FieldState<TData> = {
8269
meta: FieldMeta
8370
}
8471

85-
export type ResolveData<TData, TParentData, TName> = unknown extends TData
86-
? DeepValue<TParentData, TName>
87-
: TData
88-
8972
export type ResolveName<TParentData> = unknown extends TParentData
9073
? string
9174
: DeepKeys<TParentData>
9275

9376
export class FieldApi<
94-
TData,
9577
TParentData,
9678
TName extends DeepKeys<TParentData>,
97-
TResolvedData extends ResolveData<TData, TParentData, TName> = ResolveData<
98-
TData,
99-
TParentData,
100-
TName
101-
>,
79+
TData = DeepValue<TParentData, TName>,
10280
> {
10381
uid: number
104-
form: FieldApiOptions<TData, TParentData, TName, TResolvedData>['form']
82+
form: FieldApiOptions<TParentData, TName, TData>['form']
10583
name!: DeepKeys<TParentData>
106-
options: FieldApiOptions<TData, TParentData, TName> = {} as any
107-
store!: Store<FieldState<TResolvedData>>
108-
state!: FieldState<TResolvedData>
109-
prevState!: FieldState<TResolvedData>
84+
options: FieldApiOptions<TParentData, TName> = {} as any
85+
store!: Store<FieldState<TData>>
86+
state!: FieldState<TData>
87+
prevState!: FieldState<TData>
11088

11189
constructor(
112-
opts: FieldApiOptions<TData, TParentData, TName, TResolvedData> & {
90+
opts: FieldApiOptions<TParentData, TName, TData> & {
11391
form: FormApi<TParentData>
11492
},
11593
) {
@@ -123,7 +101,7 @@ export class FieldApi<
123101

124102
this.name = opts.name as any
125103

126-
this.store = new Store<FieldState<TResolvedData>>(
104+
this.store = new Store<FieldState<TData>>(
127105
{
128106
value: this.getValue(),
129107
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
@@ -190,7 +168,7 @@ export class FieldApi<
190168
}
191169
}
192170

193-
update = (opts: FieldApiOptions<TResolvedData, TParentData, TName>) => {
171+
update = (opts: FieldApiOptions<TParentData, TName, TData>) => {
194172
// Default Value
195173
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
196174
if (this.state.value === undefined) {
@@ -212,12 +190,12 @@ export class FieldApi<
212190
this.options = opts as never
213191
}
214192

215-
getValue = (): TResolvedData => {
193+
getValue = (): TData => {
216194
return this.form.getFieldValue(this.name) as any
217195
}
218196

219197
setValue = (
220-
updater: Updater<TResolvedData>,
198+
updater: Updater<TData>,
221199
options?: { touch?: boolean; notify?: boolean },
222200
) => {
223201
this.form.setFieldValue(this.name, updater as never, options)
@@ -241,13 +219,12 @@ export class FieldApi<
241219

242220
getInfo = () => this.form.getFieldInfo(this.name)
243221

244-
pushValue = (
245-
value: TResolvedData extends any[] ? TResolvedData[number] : never,
246-
) => this.form.pushFieldValue(this.name, value as any)
222+
pushValue = (value: TData extends any[] ? TData[number] : never) =>
223+
this.form.pushFieldValue(this.name, value as any)
247224

248225
insertValue = (
249226
index: number,
250-
value: TResolvedData extends any[] ? TResolvedData[number] : never,
227+
value: TData extends any[] ? TData[number] : never,
251228
) => this.form.insertFieldValue(this.name, index, value as any)
252229

253230
removeValue = (index: number) => this.form.removeFieldValue(this.name, index)
@@ -256,16 +233,11 @@ export class FieldApi<
256233
this.form.swapFieldValues(this.name, aIndex, bIndex)
257234

258235
getSubField = <
259-
TSubData,
260-
TSubName extends DeepKeys<TResolvedData>,
261-
TSubResolvedData extends ResolveData<
262-
DeepValue<TResolvedData, TSubName>,
263-
TResolvedData,
264-
TSubName
265-
>,
236+
TSubName extends DeepKeys<TData>,
237+
TSubData = DeepValue<TData, TSubName>,
266238
>(
267239
name: TSubName,
268-
): FieldApi<TSubData, TResolvedData, TSubName, TSubResolvedData> =>
240+
): FieldApi<TData, TSubName, TSubData> =>
269241
new FieldApi({
270242
name: `${this.name}.${name}` as never,
271243
form: this.form,
@@ -398,7 +370,7 @@ export class FieldApi<
398370

399371
validate = (
400372
cause: ValidationCause,
401-
value?: TResolvedData,
373+
value?: TData,
402374
): ValidationError[] | Promise<ValidationError[]> => {
403375
// If the field is pristine and validatePristine is false, do not validate
404376
if (!this.state.meta.isTouched) return []
@@ -416,7 +388,7 @@ export class FieldApi<
416388
return this.validateAsync(value, cause)
417389
}
418390

419-
handleChange = (updater: Updater<TResolvedData>) => {
391+
handleChange = (updater: Updater<TData>) => {
420392
this.setValue(updater, { touch: true })
421393
}
422394

packages/form-core/src/FormApi.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export type FormOptions<TData> = {
3131
}
3232

3333
export type FieldInfo<TFormData> = {
34-
instances: Record<string, FieldApi<any, TFormData, any>>
34+
instances: Record<string, FieldApi<TFormData, any, any>>
3535
} & ValidationMeta
3636

3737
export type ValidationMeta = {

packages/react-form/src/types.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import type { FieldOptions, DeepKeys } from '@tanstack/form-core'
1+
import type { FieldOptions, DeepKeys, DeepValue } from '@tanstack/form-core'
22

33
export type UseFieldOptions<
4-
TData,
54
TParentData,
65
TName extends DeepKeys<TParentData>,
7-
> = FieldOptions<TData, TParentData, TName> & {
6+
TData = DeepValue<TParentData, TName>,
7+
> = FieldOptions<TParentData, TName, TData> & {
88
mode?: 'value' | 'array'
99
}

packages/react-form/src/useField.tsx

Lines changed: 14 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
import React, { useState } from 'react'
22
import { useStore } from '@tanstack/react-store'
3-
import type {
4-
DeepKeys,
5-
DeepValue,
6-
Narrow,
7-
ResolveData,
8-
} from '@tanstack/form-core'
3+
import type { DeepKeys, DeepValue, Narrow } from '@tanstack/form-core'
94
import { FieldApi, functionalUpdate } from '@tanstack/form-core'
105
import { useFormContext, formContext } from './formContext'
116
import useIsomorphicLayoutEffect from 'use-isomorphic-layout-effect'
@@ -14,35 +9,21 @@ import type { UseFieldOptions } from './types'
149
declare module '@tanstack/form-core' {
1510
// eslint-disable-next-line no-shadow
1611
interface FieldApi<
17-
TData,
1812
TParentData,
1913
TName extends DeepKeys<TParentData>,
20-
TResolvedData extends ResolveData<TData, TParentData, TName> = ResolveData<
21-
TData,
22-
TParentData,
23-
TName
24-
>,
14+
TData = DeepValue<TParentData, TName>,
2515
> {
2616
Field: FieldComponent<TData>
2717
}
2818
}
2919

3020
export type UseField<TParentData> = <TName extends DeepKeys<TParentData>>(
31-
opts?: { name: Narrow<TName> } & UseFieldOptions<
32-
DeepValue<TParentData, TName>,
33-
TParentData,
34-
TName
35-
>,
36-
) => FieldApi<DeepValue<TParentData, TName>, TParentData, TName>
21+
opts?: { name: Narrow<TName> } & UseFieldOptions<TParentData, TName>,
22+
) => FieldApi<TParentData, TName, DeepValue<TParentData, TName>>
3723

38-
export function useField<
39-
TData,
40-
TParentData,
41-
TName extends DeepKeys<TParentData>,
42-
>(
43-
opts: UseFieldOptions<TData, TParentData, TName>,
24+
export function useField<TParentData, TName extends DeepKeys<TParentData>>(
25+
opts: UseFieldOptions<TParentData, TName>,
4426
): FieldApi<
45-
TData,
4627
TParentData,
4728
TName
4829
// Omit<typeof opts, 'onMount'> & {
@@ -95,14 +76,11 @@ export function useField<
9576
}
9677

9778
type FieldComponentProps<
98-
TData,
9979
TParentData,
10080
TName extends DeepKeys<TParentData>,
101-
TResolvedData extends ResolveData<TData, TParentData, TName>,
81+
TData = DeepValue<TParentData, TName>,
10282
> = {
103-
children: (
104-
fieldApi: FieldApi<TData, TParentData, TName, TResolvedData>,
105-
) => any
83+
children: (fieldApi: FieldApi<TParentData, TName, TData>) => any
10684
} & (TParentData extends any[]
10785
? {
10886
name?: TName
@@ -112,27 +90,22 @@ type FieldComponentProps<
11290
name: TName
11391
index?: never
11492
}) &
115-
Omit<UseFieldOptions<TData, TParentData, TName>, 'name' | 'index'>
93+
Omit<UseFieldOptions<TParentData, TName>, 'name' | 'index'>
11694

11795
export type FieldComponent<TParentData> = <
118-
TData,
11996
TName extends DeepKeys<TParentData>,
120-
TResolvedData extends ResolveData<TData, TParentData, TName> = ResolveData<
121-
TData,
122-
TParentData,
123-
TName
124-
>,
97+
TData = DeepValue<TParentData, TName>,
12598
>({
12699
children,
127100
...fieldOptions
128-
}: FieldComponentProps<TData, TParentData, TName, TResolvedData>) => any
101+
}: FieldComponentProps<TParentData, TName, TData>) => any
129102

130-
export function Field<TData, TParentData, TName extends DeepKeys<TParentData>>({
103+
export function Field<TParentData, TName extends DeepKeys<TParentData>>({
131104
children,
132105
...fieldOptions
133106
}: {
134-
children: (fieldApi: FieldApi<TData, TParentData, TName>) => any
135-
} & UseFieldOptions<TData, TParentData, TName>) {
107+
children: (fieldApi: FieldApi<TParentData, TName>) => any
108+
} & UseFieldOptions<TParentData, TName>) {
136109
const fieldApi = useField(fieldOptions as any)
137110

138111
return (

packages/vue-form/src/tests/useField.test.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ describe('useField', () => {
3030

3131
return () => (
3232
<form.Field name="firstName" defaultValue="FirstName">
33-
{({ field }: { field: FieldApi<string, Person> }) => (
33+
{({ field }: { field: FieldApi<Person, 'firstName'> }) => (
3434
<input
3535
data-testid={'fieldinput'}
3636
value={field.state.value}
@@ -68,7 +68,7 @@ describe('useField', () => {
6868
name="firstName"
6969
onChange={(value) => (value === 'other' ? error : undefined)}
7070
>
71-
{({ field }: { field: FieldApi<string, Person> }) => (
71+
{({ field }: { field: FieldApi<Person, 'firstName'> }) => (
7272
<div>
7373
<input
7474
data-testid="fieldinput"
@@ -111,7 +111,7 @@ describe('useField', () => {
111111
name="firstName"
112112
onChange={(value) => (value === 'other' ? error : undefined)}
113113
>
114-
{({ field }: { field: FieldApi<string, Person> }) => (
114+
{({ field }: { field: FieldApi<Person, 'firstName'> }) => (
115115
<div>
116116
<input
117117
data-testid="fieldinput"
@@ -159,7 +159,7 @@ describe('useField', () => {
159159
return error
160160
}}
161161
>
162-
{({ field }: { field: FieldApi<string, Person> }) => (
162+
{({ field }: { field: FieldApi<Person, 'firstName'> }) => (
163163
<div>
164164
<input
165165
data-testid="fieldinput"
@@ -211,7 +211,7 @@ describe('useField', () => {
211211
return error
212212
}}
213213
>
214-
{({ field }: { field: FieldApi<string, Person> }) => (
214+
{({ field }: { field: FieldApi<Person, 'firstName'> }) => (
215215
<div>
216216
<input
217217
data-testid="fieldinput"

0 commit comments

Comments
 (0)