-
Notifications
You must be signed in to change notification settings - Fork 407
feat(macro): make select macro choices strictly typed #2218
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat(macro): make select macro choices strictly typed #2218
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
size-limit report 📦
|
Thanks! Basically type Gender = "male" | "female";
const genger: Gender = 'male'
expectType<string>(
select(gender, {
male: "he",
other: "female",
})
) The cases for the select are not exhaustive, means you can skip one, and it should fallback to the |
I will add another test case, which doesn't contain other in the set of options!
If that's the case, should this instead be a new optional macro or option to enable exhaustiveness? I find the use case where it is exhaustive more common in our real world usage scenario than not being exhaustive ^ I guess it could be similar to Note to self:
|
5adf1cc
to
6e9adad
Compare
I'm not sure about this one, all macro is just a syntax sugar about ICU expressions and should follow theirs semantics, adding a new macro with a different behavior contradict with this architecture rule.
https://icu.unicode.org/design/formatting/select If you create a exhaustive rule that means the user will have to specify one of the options twice: type Gender = "male" | "female";
const genger: Gender = 'male'
expectType<string>(
selectExhaustive(gender, {
male: "he",
female: "female",
other: "female", // <-- still should be there even in the exhaustive version
})
) I understand your intention to make it 100% type safe and help to catch bugs when a new option added to the input type, but the underlying ICU Select was designed not considering this case. Kinda from the DX perspective, I think ergonomically would be nice to implement exhaustive / non-exhaustive based if the type SelectOptionsExhaustive<T extends string = string> = {
[key in T]: string
}
type SelectOptionsNonExhaustive<T extends string = string> = {
/** Catch-all option */
other: string
} & {
[key in T]?: string
}
type SelectOptions<T extends string = string> = SelectOptionsExhaustive<T> | SelectOptionsNonExhaustive<T> But again this will contradict with the underlying ICU Select. |
I dove into the details with ICU MessageFormat
In my opinion the implementation in application code using Lingui could be more strict than the underlying specification, since the select options in the application code are (most often? / always?) in the source language. But the option to be less strict has to be kept there for translating to other languages. I feel like using const scaleOptions = {
linear5: msg`5-point scale`,
binary: msg`Yes/no`,
written: msg`Written`
} as const
// ...
<span>{scaleOptions[question.scale]}</span> But this has the large drawback that it loses the context of these values being related to each other in the translation file. If we implemented the approach where including I still kind of like the option for I am currently rocking a global type wrapper / overload for the |
First of all, thanks for digging into the topic. Second, let's check how the message format parser would behave if you will not specify |
From quick testing ignoring the
|
6e9adad
to
e20dc0d
Compare
230039f
to
6e36dd1
Compare
Even if the parser used in the lingui is not crashing, most likely that wouldn't be a case in TMS. Example above from the message format online editor. So omitting It is better to left it empty. Also, i suppose this change might be a breaking for the users, since typing become stricter. But we can ignore it, possibly |
Makes sense. I guess this also needs runtime code changes, not only types. I can check this later
Yep, noted in the description. I guess it needs to be decided whether to treat typechecking errors as breaking or not |
6e36dd1
to
81bff9d
Compare
/** Default to fill other with empty value for compatibility with ICU spec */ | ||
other: "", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, that means SWC plugins changes would also be required
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, I guess that's in a different repo 👀
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's my attempt at implementing the same behavior on SWC side:
lingui/swc-plugin#157
Let me know if it's going totally in the wrong direction
Looks good to me. We also need to update docs for these macros, just with few sentences about this new behaviors |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since there is a changes done to the macro, you need to add a test for the macro itself covering this change
Makes sense! Thanks for being super responsive. I have been a bit busy, but I'll update this PR later |
08cf504
to
13611d1
Compare
Finally got back to this, sorry for the delay! I have added a test for the new macro functionality |
13611d1
to
33c0e4d
Compare
Description
Closes #2214, implementing stricter types for the options in the select macro.
Types of changes
Fixes #2214
Checklist