form.change Typescript definition is too strict (fails for nested fields)
onlyann opened this issue · comments
Are you submitting a bug report or a feature request?
Bug report
What is the current behavior?
Assuming
type FormValue = {
user: {
name: string;
},
items: string[]
}
Both form.change("user.name")
and form.change("items[0]")
will result in
Argument of type 'string' is not assignable to parameter of type '"user" | "items"
What is the expected behavior?
This should be considered valid.
I suggest to revert #318
As far as I know, there is no way in Typescript to express the allowed syntax and string
would be the best constraint for now.
Other information
@erikras I see that you had the same comment but somehow it got merged.
I am not sure to understand @yunyu 's answer.
Any update on this @erikras ? We also have the same issue with nested fields now.
In the linked PR (#318), @yunyu mentions a fallback.
However, it seems like this fallback is only used if no form type is provided at all!
So this will work:
const form = useForm();
form.change('some.nested.attribute')
But this will not:
const form = useForm<{some: {nested: {attribute: string}}}>();
form.change('some.nested.attribute', 'new value')
I think there are good reasons type the form and still use dot-syntax for accessors. At least for historic reasons.
If a typesafe API was to be provided, I think it would have to do something like this:
const form = useForm<{some: {nested: {attribute: string}}}>();
form.change((values) => values.some.nested.attribute, 'new value')
This was a major breaking change for us, and I would love to see it reverted.
It is totally possible to have type-safe access to nested paths, but you'd have to use arrays instead of a string for the path.
Here's one example in monocle-ts.
https://github.com/gcanti/monocle-ts/blob/a728cfc38472a10da24da27b964375634ee3d9d9/src/index.ts#L221
Earlier today I've tried to modify this library's code to accept array-based paths in addition to string-based ones, but found that to be very complicated and cumbersome as far as changing the internal functions to meet that. Some places are tightly coupled to the path being a string (e.g. sometimes the path is used to index some object, and that can't work with an array, of course). I've even tried creating a fromPath
counterpart to toPath
, but it ultimately ended up spurring some bugs I did not comprehend, even though the thing type-checked.
@erikras are you interested in changing the FormApi.change
interfaces to also accept array paths? Like mentioned above, I tried my hand at it but couldn't fully flesh out an implementation which passed all the tests.
From my understanding that type definition linked above becomes much nicer with variadic types in TS 4.0 (releasing in a month).
https://devblogs.microsoft.com/typescript/announcing-typescript-4-0-beta/#variadic-tuple-types
Having strict types with arrays instead of (or in addition to) dot notation seems like a good direction.
@resolritter you might be able to coax TS into strongly typing path arrays, but good luck coaxing it into picking out the correct type for a nested field given the path, so that to can type check the values going to your validators and field components and so on. Last time I tried something similar to that lensing approach TS just seemed too weak to report errors on nested field types when it should. Hopefully this improves with newer versions of TS though.
bump.
I really want to upgrade, but this is getting in the way.
same issue as #391
and, with TS 4.3, maybe we can do some improvement on this: #391 (comment)