Repository navigation
Regression in generic inference with JSX in v5.7+Β #62140
Copy link
Copy link
Open
Labels
Domain: JSX/TSXRelates to the JSX parser and emitterRelates to the JSX parser and emitterHelp WantedYou can do thisYou can do thisPossible ImprovementThe current behavior isn't wrong, but it's possible to see that it might be better in some casesThe current behavior isn't wrong, but it's possible to see that it might be better in some cases
Milestone
Description
π Search Terms
tsx generic
π Version & Regression Information
- This changed between versions 5.6.3 and 5.7.3
β― Playground Link
π» Code
import { defineProps as vueDefineProps } from 'vue';
declare const Comp: {
new <__VERTER__TS__T extends string = ''>(): {
$props: defineProps<__VERTER__TS__T>
};
}
(
<Comp name="foo"
onName={e => {
// @ts-expect-error this should never happen
if (e !== 'dd') {
}
}} />
);
; function TemplateBindingFN<T extends string>() {
const Props = vueDefineProps<{
name: T;
onName: (n: T) => void;
}>()
return { defineProps: Props as typeof Props }
};
export type defineProps<T extends string> = ReturnType<typeof TemplateBindingFN<T>>['defineProps']π Actual behavior
In later version the onName argument does not get the generic information resolved, defaulting to string, earlier versions 5.x infer e as 'foo'
π Expected behavior
e should be implicitly inferred based on the generic passed in name
Additional information about the issue
It seems to be caused by the type mutation of DefineProps
export type DefineProps<T, BKeys extends keyof T> = Readonly<T> & {
readonly [K in BKeys]-?: boolean
}Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
Domain: JSX/TSXRelates to the JSX parser and emitterRelates to the JSX parser and emitterHelp WantedYou can do thisYou can do thisPossible ImprovementThe current behavior isn't wrong, but it's possible to see that it might be better in some casesThe current behavior isn't wrong, but it's possible to see that it might be better in some cases
Activity
Andarist commentedon Jul 28, 2025
Bisects to #52095
Those types simplify to:
Since that PR, both intersection constituents are properly considered as types that can contextually type the
nameproperty here. The second one isn't eliminated soon enough - asT's type is still a work in progress. So thenameproperty gets typed based on__VERTER__TS__T & boolean(and that's basicallynever). And thus it widens to just astring- whereas previously it would only be typed based on__VERTER__TS__Tand given that has a string contraint... the type would not widen and it would stay as"foo".Please also remember that
Tcould be instantiated withnever, so - despiteThaving astringconstraint - that intersection member can't be easily eliminated.