@@ -43,10 +43,19 @@ export interface FieldOptions<
4343 defaultMeta ?: Partial < FieldMeta >
4444}
4545
46- export type FieldApiOptions < TData , TFormData > = FieldOptions <
47- TData ,
48- TFormData
49- > & {
46+ export interface FieldApiOptions <
47+ _TData ,
48+ TFormData ,
49+ /**
50+ * This allows us to restrict the name to only be a valid field name while
51+ * also assigning it to a generic
52+ */
53+ TName = unknown extends TFormData ? string : DeepKeys < TFormData > ,
54+ /**
55+ * If TData is unknown, we can use the TName generic to determine the type
56+ */
57+ TData = unknown extends _TData ? DeepValue < TFormData , TName > : _TData ,
58+ > extends FieldOptions < _TData , TFormData , TName , TData > {
5059 form : FormApi < TFormData >
5160}
5261
@@ -65,35 +74,45 @@ export type FieldState<TData> = {
6574 meta : FieldMeta
6675}
6776
68- /**
69- * TData may not be known at the time of FieldApi construction, so we need to
70- * use a conditional type to determine if TData is known or not.
71- *
72- * If TData is not known, we use the TFormData type to determine the type of
73- * the field value based on the field name.
74- */
75- type GetTData < Name , TData , TFormData > = unknown extends TData
76- ? DeepValue < TFormData , Name >
77- : TData
78-
79- export class FieldApi < TData , TFormData > {
77+ type GetTData <
78+ TData ,
79+ TFormData ,
80+ Opts extends FieldApiOptions < TData , TFormData > ,
81+ > = Opts extends FieldApiOptions <
82+ infer _TData ,
83+ infer _TFormData ,
84+ infer _TName ,
85+ infer RealTData
86+ >
87+ ? RealTData
88+ : never
89+
90+ export class FieldApi <
91+ _TData ,
92+ TFormData ,
93+ Opts extends FieldApiOptions < _TData , TFormData > = FieldApiOptions <
94+ _TData ,
95+ TFormData
96+ > ,
97+ TData extends GetTData < _TData , TFormData , Opts > = GetTData <
98+ _TData ,
99+ TFormData ,
100+ Opts
101+ > ,
102+ > {
80103 uid : number
81- form : FormApi < TFormData >
104+ form : Opts [ 'form' ]
82105 name ! : DeepKeys < TFormData >
83- /**
84- * This is a hack that allows us to use `GetTData` without calling it everywhere
85- *
86- * Unfortunately this hack appears to be needed alongside the `TName` hack
87- * further up in this file. This properly types all of the internal methods,
88- * while the `TName` hack types the options properly
89- */
90- _tdata ! : GetTData < typeof this . name , TData , TFormData >
91- store ! : Store < FieldState < typeof this . _tdata > >
92- state ! : FieldState < typeof this . _tdata >
93- prevState ! : FieldState < typeof this . _tdata >
94- options : FieldOptions < typeof this . _tdata , TFormData > = { } as any
95-
96- constructor ( opts : FieldApiOptions < TData , TFormData > ) {
106+ options : Opts = { } as any
107+ store ! : Store < FieldState < TData > >
108+ state ! : FieldState < TData >
109+ prevState ! : FieldState < TData >
110+
111+ constructor (
112+ opts : Opts & {
113+ form : FormApi < TFormData >
114+ } ,
115+ ) {
97116 this . form = opts . form
98117 this . uid = uid ++
99118 // Support field prefixing from FieldScope
@@ -104,7 +123,7 @@ export class FieldApi<TData, TFormData> {
104123
105124 this . name = opts . name as any
106125
107- this . store = new Store < FieldState < typeof this . _tdata > > (
126+ this . store = new Store < FieldState < TData > > (
108127 {
109128 value : this . getValue ( ) ,
110129 // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
@@ -138,7 +157,7 @@ export class FieldApi<TData, TFormData> {
138157
139158 mount = ( ) => {
140159 const info = this . getInfo ( )
141- info . instances [ this . uid ] = this
160+ info . instances [ this . uid ] = this as never
142161
143162 const unsubscribe = this . form . store . subscribe ( ( ) => {
144163 this . store . batch ( ( ) => {
@@ -167,7 +186,7 @@ export class FieldApi<TData, TFormData> {
167186 }
168187 }
169188
170- update = ( opts : FieldApiOptions < typeof this . _tdata , TFormData > ) => {
189+ update = ( opts : FieldApiOptions < TData , TFormData > ) => {
171190 // Default Value
172191 // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
173192 if ( this . state . value === undefined ) {
@@ -189,12 +208,12 @@ export class FieldApi<TData, TFormData> {
189208 this . options = opts as never
190209 }
191210
192- getValue = ( ) : typeof this . _tdata => {
211+ getValue = ( ) : TData => {
193212 return this . form . getFieldValue ( this . name )
194213 }
195214
196215 setValue = (
197- updater : Updater < typeof this . _tdata > ,
216+ updater : Updater < TData > ,
198217 options ?: { touch ?: boolean ; notify ?: boolean } ,
199218 ) => {
200219 this . form . setFieldValue ( this . name , updater as never , options )
@@ -218,26 +237,21 @@ export class FieldApi<TData, TFormData> {
218237
219238 getInfo = ( ) => this . form . getFieldInfo ( this . name )
220239
221- pushValue = (
222- value : typeof this . _tdata extends any [ ]
223- ? ( typeof this . _tdata ) [ number ]
224- : never ,
225- ) => this . form . pushFieldValue ( this . name , value as any )
240+ pushValue = ( value : TData extends any [ ] ? TData [ number ] : never ) =>
241+ this . form . pushFieldValue ( this . name , value as any )
226242
227243 insertValue = (
228244 index : number ,
229- value : typeof this . _tdata extends any [ ]
230- ? ( typeof this . _tdata ) [ number ]
231- : never ,
245+ value : TData extends any [ ] ? TData [ number ] : never ,
232246 ) => this . form . insertFieldValue ( this . name , index , value as any )
233247
234248 removeValue = ( index : number ) => this . form . removeFieldValue ( this . name , index )
235249
236250 swapValues = ( aIndex : number , bIndex : number ) =>
237251 this . form . swapFieldValues ( this . name , aIndex , bIndex )
238252
239- getSubField = < TName extends DeepKeys < typeof this . _tdata > > ( name : TName ) =>
240- new FieldApi < DeepValue < typeof this . _tdata , TName > , TFormData > ( {
253+ getSubField = < TName extends DeepKeys < TData > > ( name : TName ) =>
254+ new FieldApi < DeepValue < TData , TName > , TFormData > ( {
241255 name : `${ this . name } .${ name } ` as never ,
242256 form : this . form ,
243257 } )
@@ -371,7 +385,7 @@ export class FieldApi<TData, TFormData> {
371385
372386 validate = (
373387 cause : ValidationCause ,
374- value ?: typeof this . _tdata ,
388+ value ?: TData ,
375389 ) : ValidationError [ ] | Promise < ValidationError [ ] > => {
376390 // If the field is pristine and validatePristine is false, do not validate
377391 if ( ! this . state . meta . isTouched ) return [ ]
@@ -389,7 +403,7 @@ export class FieldApi<TData, TFormData> {
389403 return this . validateAsync ( value , cause )
390404 }
391405
392- handleChange = ( updater : Updater < typeof this . _tdata > ) => {
406+ handleChange = ( updater : Updater < TData > ) => {
393407 this . setValue ( updater , { touch : true } )
394408 }
395409
0 commit comments