-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Incorrect Generic Constraint with Union when Nested #51969
Comments
Ah, this is a classic. Duplicate of #35873/#30581. The first thing to note is that the nested generic is a red herring. You can remove it completely and see the same puzzling behavior: const Form = <C extends CreateFormProps | EditFormProps>({
setModel,
model,
isEditing,
}: C) => {
setModel(model); // error
if (isEditing) {
setModel(model) // works
} else {
setModel(model) // works
}
} The error stems from the fact that
is incorrect. setModel: ((model: TempModel) => void) | ((model: CreateTempModel) => void)
// reduces to
setModel: (model: TempModel & CreateTempModel) => void Since the function could have either signature, you have to call it with an argument that would satisfy either signature—that is, a type that satisfies both What the compiler doesn’t understand, the way you’ve written it here, is that these two unions are correlated. I think if you study #30581 and the PR that closed it, you can probably find a way to rewrite this that works. |
@andrewbranch Interesting and thank you! I got two versions working (see the second one as it is very interesting) The model of the union of functions resolving to the intersection makes sense. I think the best resolution here is something along the lines of this Playground Link type UpsertMap = { "create": CreateTempModel, "update": TempModel };
type FormProps<K extends keyof UpsertMap = keyof UpsertMap> = {
setModel: (model: UpsertMap[K]) => void;
model: UpsertMap[K];
formType: K;
} I still don't quite understand how the That said. This also works! Playground Link type FormProps<K extends CreateTempModel | TempModel = CreateTempModel | TempModel> = {
setModel: (model: K) => void;
model: K;
isEditing: boolean;
}
const Form = ({
setModel, model, isEditing,
}: FormProps) => {
setModel(model);
} That really doesn't make sense to me, but I guess somehow it is correctly constraining? |
This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes. |
@wilwade I know this issue is 3 weeks old, but I felt I should answer this:
From the compiler's point of view, you have a |
Bug Report
🔎 Search Terms
Generic
🕗 Version & Regression Information
⏯ Playground Link
Playground link with relevant code
💻 Code
🙁 Actual behavior
The compiler resolves the type of setModel as
(model: TempModel) => void;
🙂 Expected behavior
The compiler resolves the type of setModel as
(model: TempModel | CreateTempModel) => void;
Additional Complexity
The playground code DOES work in another case.
If we add an additional constraint of
isEditing
this will NOT throw the error:The text was updated successfully, but these errors were encountered: