-
Notifications
You must be signed in to change notification settings - Fork 852
Description
tsgo reports a false positive TS2488 when using a generic JSX component where a type parameter should be inferred from one prop (selector) and consumed in another (children).
tsgo fails to infer the type parameter from the JSX prop and falls back to the default, causing a spurious error. The equivalent non-JSX function call works correctly.
tsc (TypeScript 5.9.3) reports no error on the same code.
Minimal Reproduction
https://github.com/theoludwig/oxlint-tsgolint-issue-135
interface State {
value: boolean
}
declare const Subscribe: <TSelected = State>(props: {
selector?: (state: State) => TSelected
children: (state: TSelected) => void
}) => React.ReactNode
const _result = (
<Subscribe
selector={(state) => {
return [state.value]
}}
>
{([value = false]) => {
console.log(value)
}}
</Subscribe>
)Expected behavior
TSelected should be inferred as boolean[] from the selector return type (same as tsc). No error should be reported.
Actual behavior
tsgo does not infer TSelected from the selector prop and falls back to the default (State). This causes:
TS2488: Type 'State' must have a '[Symbol.iterator]()' method that returns an iterator.
on the array destructuring pattern [value = false] in children.
Key observation: JSX-specific
The same pattern as a regular function call works correctly in tsgo, no error:
Subscribe({
selector: (state) => {
return [state.value]
},
children: ([value = false]) => {
console.log(value)
},
})The bug only manifests when the generic function is used as a JSX component with children passed as JSX children (between opening and closing tags) rather than as a direct prop.
Environment
- Detected via
oxlint 1.48.0with--type-check --type-aware(which uses tsgo viaoxlint-tsgolint 0.14.0) tsc(TypeScript 5.9.3): no error- This issue was not present with
oxlint-tsgolint 0.12.2and appeared after0.13.0which updated the typescript-go submodule
Real-world impact
This affects all uses of @tanstack/react-form's form.Subscribe component, which uses exactly this pattern — a selector prop that transforms FormState into a derived value, and children that receives the selected value.