T
TanStack2w ago
helpful-purple

How to get listener fn type?

I have a very simple goal on my form that i use with useAppForm. I have an onChange inside listener and i'm passing a function to it. All i need, is to be able to type the parameters of my custom function to match onChange. Here is an example:
<form.AppField
listeners={{
onChange: onPriceChangeListener,
}}>
<form.AppField
listeners={{
onChange: onPriceChangeListener,
}}>
and my onPriceChangeListener function:
const onPriceChangeListener = (params: WHAT_SHOULD_BE_TYPE?) => {};
const onPriceChangeListener = (params: WHAT_SHOULD_BE_TYPE?) => {};
Thanks!
6 Replies
rising-crimson
rising-crimson2w ago
there's currently no way to extract the exact type to an external function. One reason is that not all listeners have the same data (onSubmit listener vs. onChange). It really depends on what you actually want to extract in this case. What part of the field API do you want to access? do you only need the value? Do you plan on changing other values etc. in this case, you mostly get access to two things: params: { value, fieldApi } value is the value of the field, fieldApi is the typed version of your field to make calls to.
helpful-purple
helpful-purpleOP2w ago
well i need to access fieldApi, for example setValue and of course don't want to manully type everything. I belive those both params { value, fieldApi } are part of the field object, so yeah i'd like get that part so that i can pass it around in a typed manner.
rising-crimson
rising-crimson2w ago
if you have proposals for how to create the typed version, feel free to share! I was thinking of two ways to do it:
// outside components
const myListener = createListener(
formOptions,
'fieldName',
{
onChange: ({ value, fieldApi }) => {/* ... */}
}
)

// inside components
const myListener = form.createListener('fieldName', { /* ... */ })
// outside components
const myListener = createListener(
formOptions,
'fieldName',
{
onChange: ({ value, fieldApi }) => {/* ... */}
}
)

// inside components
const myListener = form.createListener('fieldName', { /* ... */ })
the simpler way is to still use inline functions and pass what's required. For example, handleChange or setValue accept updater functions. So you can do:
function formatMyValue(val: string): string {
return val.toUpperCase()
}

// ...
listeners={{
onBlur: ({ fieldApi }) => fieldApi.handleChange(formatMyValue)
}}
function formatMyValue(val: string): string {
return val.toUpperCase()
}

// ...
listeners={{
onBlur: ({ fieldApi }) => fieldApi.handleChange(formatMyValue)
}}
perhaps a TanStack Table approach wouldn't be that bad either:
const formHelper = createHelper(formOptions)

formHelper.listener('fieldName', { /* ... */ })
formHelper.validator('fieldName', { /* ... */ })

// inside component
const formHelper = form.getHelper();
const formHelper = createHelper(formOptions)

formHelper.listener('fieldName', { /* ... */ })
formHelper.validator('fieldName', { /* ... */ })

// inside component
const formHelper = form.getHelper();
helpful-purple
helpful-purpleOP2w ago
i found this in docs AnyFieldApi this is fieldApi type no?
rising-crimson
rising-crimson2w ago
a very generic one. It has no info on what the fieldApi's value is or what form it came from suitable if you only need meta properties like isTouched etc.
helpful-purple
helpful-purpleOP2w ago
I was thinking something similar to z.infer: ApiForm<typeof form>

Did you find this page helpful?