Repository navigation
Fix {{fn}} with generic callbacks no longer inferring from the arg type - #1248
Merged
NullVoxPopuli merged 1 commit intoSep 23, 2026
Merged
Conversation
…ried keywords Since typed-ember#1189, every `{{fn f a}}` was emitted as a `(resolve(fn)(f, a), bindPositional(f, a))` comma pair. The validating call on the left of the comma has no contextual type, so a callback whose type parameters depend on each other (`<K extends keyof M, V extends M[K]>`) could no longer be inferred and valid code was rejected. The comma pair was only needed inside the result half of the `{{component}}`/`{{helper}}`/`{{modifier}}` pair, where a real `fn` call collapses `bindInvokable`'s inference (typed-ember#1147). Now: - inside `bindInvokable(...)` args, `fn` emits just `bindPositional(...)` (the keyword half next to it already validates the arguments) - everywhere else, `fn` emits a plain `resolve(fn)(...)` call again, so it gets its slot's contextual type `bindPositional`'s `Bound` is also made `const`, so literal bound args like `"name"` aren't widened to `string` (which made the result `never`). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1247
Since #1189, every
{{fn f a}}compiles to a comma pair:The
fncall on the left has no contextual type. That's fine for most callbacks, but not for a generic one like<K extends keyof Person, V extends Person[K]>(key: K, value: V) => void: TypeScript needs the expected type to work outV. Without it,Vfalls back tostring | numberand valid code is rejected.Fix
The comma pair is only needed in one place: inside the
bindInvokable(...)half of{{component}}/{{helper}}/{{modifier}}, where a realfncall collapses inference (#1147). So now:bindInvokable(...),fnbecomes justbindPositional(...). The keyword call next to it already validates the arguments.fnis a plainresolve(fn)(...)call again, like in ≤ 1.8.8, so it gets the expected type from its slot.While in there:
bindPositional'sBoundis nowconst. Without that, a literal bound argument like"name"widened tostring, and the result becamenever.Tests
fn-generic-callback.test.gtswith the repro from the issue, plus a mismatched callback that must still errorfnhelper in combination withcomponenthelper #1147 guard (fn-in-nested-args.test.gts) andglobals/fn.gtsstill pass unchangedfninside abind-invokablekeywordNot fixed here
(component Field onChange=(fn this.update "name"))with the same generic callback still errors, and a mismatchedfnbind inside(component ...)on a generic component isn't caught. Both behave the same onmain, so they aren't regressions. The keyword's own validation call doesn't givefna useful expected type there. That's probably worth a separate issue.🤖 Generated with Claude Code