You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Attributes fail on components whose conditional Element type is instantiated with an unresolved generic #14
Same setup as #12. Filed via Claude Code on NullVoxPopuli's behalf.
Inside a generic component, passing one of its own type params into another component's generic that feeds a conditional Element type makes every attribute on the invocation fail:
tsc --runExternalCode: error TS2345: Argument of type '{ id: "x"; }' is not assignable to parameter of type 'Partial<((IsFake extends true ? HTMLDivElement : HTMLButtonElement) extends null ? unknown : ...) extends HTMLElement ? ... : ...>'.
(Real-world shape: luna's Button with AsDiv fed by a Select component's own IsFake type param; every attribute on the invocation errored.) Looks like TS7 declines to evaluate the deferred conditional the way TS6 does. Workaround we shipped: widen the getter to boolean so the conditional resolves.
This is not a TypeScript 7 difference. TypeScript 5.9 on the transformed text reports the same error. ember-tsc hides it: the diagnostic anchors on generated text that no Volar verification mapping covers, and Volar drops diagnostics it cannot map back. Glint's template-to-typescript.ts describes this gap in its wideVerification comments. The mapper maps every synthesized region back to the template construct that produced it, so the error shows.
The types that reject the code live in @glint/template:
#24 records each in test/diagnostics-tests/upstream-differences/ so a change on either side shows up. The mapper keeps reporting them: dropping diagnostics on synthesized text would also hide real errors such as a missing required argument. Next step is a Glint report, after a check against the current Glint release.
This investigation was done with Claude (via Claude Code) — apologies in advance if it missed something; corrections welcome.
Like #13, this reproduces standalone under both TS 6.0.3 and TS 7.1 nightly when the transformed output is checked directly (with ember-source/types + @glint/ember-tsc/types referenced) — so it's not a mapper or TS 7 divergence, it's inherent to how glint's attribute checking interacts with generic-dependent Element types.
Mechanism
Luna's Button declares (property-level generics, both defaulted):
and applyAttributes<T extends Element>(element: T, attrs: Partial<AttributesForElement<T>>) — where AttributesForElement<T> is itself a chain of conditionals over T — can never evaluate, so every attribute (even universally-valid data-*) fails:
error TS2353: Object literal may only specify known properties, and '"data-x"' does not exist in type
'Partial<((Href extends string ? HTMLAnchorElement : HTMLButtonElement) extends null ? unknown : ...) extends HTMLElement ? ... : ...>'
Identical output from both compilers. Defaults on the generics don't help — the deferral comes from the outer component's unresolved parameter, not from Button's own parameters lacking defaults.
Options
Consumer-side (recommended, what we'll do in optro-frontend): generic wrappers shouldn't thread unresolved type params into Element-selecting args. Passing a concrete string | undefined makes the conditional evaluate (to HTMLButtonElement — slightly imprecise when an href is present, but checkable).
@glint/template-side: there's no type-level way to detect "deferred conditional" and fall back, short of weakening applyAttributes for everyone (e.g. attrs: Partial<AttributesForElement<T>> | DataAttributes). I don't think that trade is worth it, but noting it for completeness.
Happy to close this as by-design once the guidance is written down somewhere (docs / known-issues).
Activity
Document the Node 22 launcher failure and the known upstream differences
NullVoxPopuli-ai-agent commentedon Aug 27, 2026
This is not a TypeScript 7 difference. TypeScript 5.9 on the transformed text reports the same error.
ember-tschides it: the diagnostic anchors on generated text that no Volar verification mapping covers, and Volar drops diagnostics it cannot map back. Glint'stemplate-to-typescript.tsdescribes this gap in itswideVerificationcomments. The mapper maps every synthesized region back to the template construct that produced it, so the error shows.The types that reject the code live in
@glint/template:Record<string, never>has an index signature, soComponentSignatureArgsin-private/signature.d.tstakes the{ Named; Positional }branch and both resolve tonever.Directlooks clean only because a lowercase<one />is an element, not a component.Elementover an unresolved type parameter never resolves, soPartial<...>accepts no attribute.{{component Comp a="hi"}}yields a curriedInvokable, andContentValueaccepts onlyComponentReturn<{}, any>.#24 records each in
test/diagnostics-tests/upstream-differences/so a change on either side shows up. The mapper keeps reporting them: dropping diagnostics on synthesized text would also hide real errors such as a missing required argument. Next step is a Glint report, after a check against the current Glint release.NullVoxPopuli commentedon Aug 27, 2026
Note
This investigation was done with Claude (via Claude Code) — apologies in advance if it missed something; corrections welcome.
Like #13, this reproduces standalone under both TS 6.0.3 and TS 7.1 nightly when the transformed output is checked directly (with
ember-source/types+@glint/ember-tsc/typesreferenced) — so it's not a mapper or TS 7 divergence, it's inherent to how glint's attribute checking interacts with generic-dependentElementtypes.Mechanism
Luna's Button declares (property-level generics, both defaulted):
When a generic wrapper component threads its own unresolved type parameter into
@href/@shouldRenderAsDiv:Hrefstays unresolved insideOuter's body, so Button'sElementis a deferred conditional type. The transform emits:and
applyAttributes<T extends Element>(element: T, attrs: Partial<AttributesForElement<T>>)— whereAttributesForElement<T>is itself a chain of conditionals overT— can never evaluate, so every attribute (even universally-validdata-*) fails:Identical output from both compilers. Defaults on the generics don't help — the deferral comes from the outer component's unresolved parameter, not from Button's own parameters lacking defaults.
Options
Element-selecting args. Passing a concretestring | undefinedmakes the conditional evaluate (toHTMLButtonElement— slightly imprecise when an href is present, but checkable).@glint/template-side: there's no type-level way to detect "deferred conditional" and fall back, short of weakeningapplyAttributesfor everyone (e.g.attrs: Partial<AttributesForElement<T>> | DataAttributes). I don't think that trade is worth it, but noting it for completeness.Happy to close this as by-design once the guidance is written down somewhere (docs / known-issues).