You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[HOLD for payment 2024-02-26] [TS Migration] Improve form validation return type #35318
Currently, the object returned by validate is just a Record<string, string>, but we know that the return type should be a map of formInputID: translationKey, so we're missing an opportunity to be precise and expressive with our type definitions. Some more specific problems with this implementation are:
It's easy to put whatever string you want in the return type (for example, I was mistakenly using translate(translationKey), when all I needed was translationKey).
If you use a constant for a form inputID (which is a good practice), then you'll get a type error referencing it in the return type of validate and have to cast it to a normal string (with as string).
constFORM_IDS={ADD_DEBIT_CARD: 'AddDebitCardForm',}asconst;// TODO: how can we enforce that all the values of FORM_IDS are included as keys in this,// without losing type informationconstINPUT_IDS={[FORM_IDS.ADD_DEBIT_CARD]: {SETUP_COMPLETE: 'setupComplete',},}asconst;
But that doesn't enforce that all values from FORM_IDS are included as keys in INPUT_IDS. It also makes us lose type information instead of SETUP_COMPLETE: 'setupComplete', we just have Record<string, string>.
Maybe there's a type-fest utility that can help here? Exact, perhaps? We essentially want a mapped type as a constant, but I wasn't able to figure out how to accomplish that.
Then, I got stuck on the next part as well. I was attempting to create a type from FORM_IDS and INPUT_IDS such that:
every form has a base set of properties
every form defines types for all the inputIDs it defined in INPUT_IDS
I tried this:
typeFormData={[FORM_IDS.ADD_DEBIT_CARD]: {// TS1170: A computed property name in a type literal must refer to an expression whose type is a literal type or a 'unique symbol' type[INPUT_IDS[FORM_IDS.ADD_DEBIT_CARD].SETUP_COMPLETE]: boolean,},};
This doesn't work, and again we'd have a similar struggle ensuring that all forms and inputIDs are represented.
I also ran into some trouble adding RadioButtons as a ValidInput, specifically around the onPress prop. Currently onPress is defined to receive a single GestureResponderEvent argument, but in reality it can receive different treatment depending on the input that it's used with.
I think the root cause for this problem, essentially, is that BaseInputProps is incorrect, in that there's nothing to ensure that all of the inputs accept those props as they're defined.
Another thing I found a bit confusing was that FormValueType is defined loosely as string | boolean | Date, but I'd think that the value type would depend on which form is being referenced.
For example, if we're talking about the FormValueType for AddDebitCardForm, it would basically be: ValueOf<AddDebitCardForm>
Kind of dumping a lot of ideas here, but that's partially because I'm having difficulty wrapping my head around a lot of this, and just trying to make sense of it.
I think the root cause for this problem, essentially, is that BaseInputProps is incorrect, in that there's nothing to ensure that all of the inputs accept those props as they're defined.
Yes BaseInputProps is the root issue, I'll fix it in a follow-up.
Another thing I found a bit confusing was that FormValueType is defined loosely as string | boolean | Date, but I'd think that the value type would depend on which form is being referenced.
But that doesn't enforce that all values from FORM_IDS are included as keys in INPUT_IDS. It also makes us lose type information instead of SETUP_COMPLETE: 'setupComplete', we just have Record<string, string>.
Maybe there's a type-fest utility that can help here? Exact, perhaps? We essentially want a mapped type as a constant, but I wasn't able to figure out how to accomplish that.
When I create INPUT_IDS mapping I'll make sure it requires to provide all FORM_IDS as keys, it may be complicated but worth trying for sure 👍
Another NAB improvement that would be nice to see is if we could eliminate the need to define every form key and type twice – once for the form and again for the form draft. This is another thing I couldn't figure out how to do without losing type information. I tried something like this:
But that doesn't quite work. I did find this complicated TS code that provides a better-typed version of Object.entries, but it still didn't make it clear how to accomplish what I was trying to.
Activity
blazejkustra commentedon Jan 29, 2024
I would love to work on this one 😄
roryabraham commentedon Jan 31, 2024
This is kind of blocking my work on https://github.com/Expensify/App/pull/34925/files, and despite lots of effort trying to make progress on it, I'm unfortunately kind of stuck.
I've tried something like this:
I've tried this:
But that doesn't enforce that all values from
FORM_IDSare included as keys inINPUT_IDS. It also makes us lose type information instead ofSETUP_COMPLETE: 'setupComplete', we just haveRecord<string, string>.Maybe there's a
type-festutility that can help here?Exact, perhaps? We essentially want a mapped type as a constant, but I wasn't able to figure out how to accomplish that.Then, I got stuck on the next part as well. I was attempting to create a type from
FORM_IDSandINPUT_IDSsuch that:INPUT_IDSI tried this:
This doesn't work, and again we'd have a similar struggle ensuring that all forms and inputIDs are represented.
roryabraham commentedon Jan 31, 2024
I also ran into some trouble adding
RadioButtonsas aValidInput, specifically around theonPressprop. CurrentlyonPressis defined to receive a singleGestureResponderEventargument, but in reality it can receive different treatment depending on the input that it's used with.I think the root cause for this problem, essentially, is that
BaseInputPropsis incorrect, in that there's nothing to ensure that all of the inputs accept those props as they're defined.roryabraham commentedon Jan 31, 2024
Another thing I found a bit confusing was that
FormValueTypeis defined loosely asstring | boolean | Date, but I'd think that the value type would depend on which form is being referenced.For example, if we're talking about the
FormValueTypeforAddDebitCardForm, it would basically be:ValueOf<AddDebitCardForm>roryabraham commentedon Jan 31, 2024
Kind of dumping a lot of ideas here, but that's partially because I'm having difficulty wrapping my head around a lot of this, and just trying to make sense of it.
blazejkustra commentedon Jan 31, 2024
Yes BaseInputProps is the root issue, I'll fix it in a follow-up.
I'll try to fix it 👍
blazejkustra commentedon Jan 31, 2024
When I create INPUT_IDS mapping I'll make sure it requires to provide all FORM_IDS as keys, it may be complicated but worth trying for sure 👍
roryabraham commentedon Jan 31, 2024
Another NAB improvement that would be nice to see is if we could eliminate the need to define every form key and type twice – once for the form and again for the form draft. This is another thing I couldn't figure out how to do without losing type information. I tried something like this:
But that doesn't quite work. I did find this complicated TS code that provides a better-typed version of
Object.entries, but it still didn't make it clear how to accomplish what I was trying to.roryabraham commentedon Feb 6, 2024
Reviewed @blazejkustra's WIP PR
14 remaining items
melvin-bot commentedon Feb 23, 2024
Triggered auto assignment to @MitchExpensify (
NewFeature), see https://stackoverflowteams.com/c/expensify/questions/14418#:~:text=BugZero%20process%20steps%20for%20feature%20requests for more details.roryabraham commentedon Feb 23, 2024
flagging as new feature to handle C+ payment
MitchExpensify commentedon Feb 26, 2024
Reminder set to pay tomorrow
abdulrahuman5196 commentedon Feb 26, 2024
No BZ checklist since we improved the TS representation of Form component
cc: @MitchExpensify
melvin-bot commentedon Feb 26, 2024
Payment Summary
Upwork Job
BugZero Checklist (@MitchExpensify)
MitchExpensify commentedon Feb 26, 2024
Offer here @abdulrahuman5196 https://www.upwork.com/nx/wm/offer/101083068
abdulrahuman5196 commentedon Feb 26, 2024
@MitchExpensify accepted the offer
MitchExpensify commentedon Feb 26, 2024
paid, contract ended!