Skip to content

Fix problem with transitive generics in Signatures#613

Closed
gossi wants to merge 2 commits intotyped-ember:mainfrom
gossi:allow-generics-in-signatures
Closed

Fix problem with transitive generics in Signatures#613
gossi wants to merge 2 commits intotyped-ember:mainfrom
gossi:allow-generics-in-signatures

Conversation

@gossi
Copy link
Collaborator

@gossi gossi commented Aug 17, 2023

Potential fix to #610

I was applying the fix as part of this PR locally on my PR emberjs/ember-element-helper#107 and see if in my type-test-component:

import Component from '@glimmer/component';
import type { ElementSignature, ElementFromTagName } from 'ember-element-helper';

interface ElementReceiverSignature<T extends string = 'article'> {
  Element: ElementFromTagName<T>;
  Args: {
    tag: ElementSignature<T>['Return'];
  };
  Blocks: {
    default: [];
  }
}

export default class ElementReceiver<T extends string> extends Component<ElementReceiverSignature<T>> {}
{{#let @tag as |Tag|}}
  {{!@glint-ignore}}
  <Tag id="content" ...attributes>{{yield}}</Tag>
{{/let}}

I was able to remove the line {{!@glint-ignore}} and if the type linting still passes, which is the case.

So, yes this is a potential fix, but I share the same concerns as @dfreeman this might come with side-effects.

So I'll make it a draft PR.

@chriskrycho
Copy link
Member

Thanks for opening this! The fact that CI is ✅ is a great initial sign – one of us will try to review in detail shortly.

@dfreeman
Copy link
Member

This should include, at a minimum, a new test case for the scenario this is intended to fix. Otherwise there's nothing to prevent us from flipping this back in the future and causing the same problem again

(I'd also recommend coming up with a more specific title for this PR, since that's what will go in the release notes—we clearly already "allow generics in signatures" in the general case, since many built-ins like let and each require that 😉)

Comment on lines +48 to +49
? NonNullable<Element> extends never
// ? Element extends null
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a temporary revert. That is to write failing tests, which when switching back to the fix should be resolved.

Positional: []
}>();

expectTypeOf<ComponentSignatureArgs<ElementReceiverSignature<null>>>().toEqualTypeOf<{
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, this line is the problematic part here, I'd say. For what I think needs to be tested, is how the components are invoked, rather than the static definition?

That is, in invocation, this should be null. But this is obviously a failure:

Type 'null' does not satisfy the constraint 'string'.

To my knowledge, to properly test this, is to provide broken types. How to do that?

@gossi
Copy link
Collaborator Author

gossi commented Sep 9, 2023

I added some tests. I copied over all the relevant types from (element) helper as well as a component receiving it. Feels a lot, but makes it accurate. If this can be less types, please let me know.

I also left comments where I got stuck. I think, I need to test broken/invalid types, in a environment with correct types?

@gossi gossi changed the title Allow generics in Signatures Fix problem with transitive generics in Signatures Sep 9, 2023
@wozny1989
Copy link

Hi @gossi! Just wondering if you’re planning to work on this at some point.

@gossi
Copy link
Collaborator Author

gossi commented May 5, 2025

I stopped. Iirc back then too much red showed up - and I didn't wanted to go through all this as it didn't seem much related to what I changed. However since then a lot changed on the glint repo itself. Feel free to pick it up.

@gossi gossi force-pushed the allow-generics-in-signatures branch from 420bdbc to f79c9c5 Compare July 17, 2025 15:15
@wagenet
Copy link
Contributor

wagenet commented Jul 18, 2025

I think resolving this issue is going to be a bit of a blocker for my team adopting Glint v2.

johanrd added a commit to johanrd/glint that referenced this pull request Mar 14, 2026
…components

Removes conditionals from the Element type pipeline that deferred for
generic conditional types like ElementFromTagName<T>:

1. ComponentSignatureElement: returns Element directly instead of
   NonNullable<Element> extends never check (which deferred to unknown).

2. ComponentReturn: removes El extends Element ? El : null (another
   deferral point). El flows through directly.

This fixes both reported errors from typed-ember#610: <Tag> and ...attributes
now work correctly inside components with conditional Element types.
Based on draft PR typed-ember#613 by @gossi.
johanrd added a commit to johanrd/glint that referenced this pull request Mar 14, 2026
…components

Removes conditionals from the Element type pipeline that deferred for
generic conditional types like ElementFromTagName<T>:

1. ComponentSignatureElement: returns Element directly instead of
   NonNullable<Element> extends never check (which deferred to unknown).

2. ComponentReturn: removes El extends Element ? El : null (another
   deferral point). El flows through directly.

This fixes both reported errors from typed-ember#610: <Tag> and ...attributes
now work correctly inside components with conditional Element types.
Based on draft PR typed-ember#613 by @gossi.
johanrd added a commit to johanrd/glint that referenced this pull request Mar 15, 2026
…omponent signatures

Two changes eliminate deferred conditional chains that collapsed
ElementFromTagName<T> to unknown when T was generic:

1. ComponentSignatureElement: replace NonNullable<Element> extends never
   with Element extends null. The old NonNullable check deferred for
   unresolved conditionals; the new null check only fires for literal
   null (preserving null → unknown for ComponentLike equivalence).

2. ComponentReturn: replace El extends Element ? El : null with
   El extends null ? unknown : El. The old Element check deferred for
   conditional types; the new null check doesn't because null is concrete.

Based on draft PR typed-ember#613 by @gossi.
johanrd added a commit to johanrd/glint that referenced this pull request Mar 15, 2026
…omponent signatures

Two changes eliminate deferred conditional chains that collapsed
ElementFromTagName<T> to unknown when T was generic:

1. ComponentSignatureElement: replace NonNullable<Element> extends never
   with Element extends null. The old NonNullable check deferred for
   unresolved conditionals; the new null check only fires for literal
   null (preserving null → unknown for ComponentLike equivalence).

2. ComponentReturn: replace El extends Element ? El : null with
   El extends null ? unknown : El. The old Element check deferred for
   conditional types; the new null check doesn't because null is concrete.

Based on draft PR typed-ember#613 by @gossi.
johanrd added a commit to johanrd/glint that referenced this pull request Mar 15, 2026
…omponent signatures

Two changes eliminate deferred conditional chains that collapsed
ElementFromTagName<T> to unknown when T was generic:

1. ComponentSignatureElement: replace NonNullable<Element> extends never
   with Element extends null. The old NonNullable check deferred for
   unresolved conditionals; the new null check only fires for literal
   null (preserving null → unknown for ComponentLike equivalence).

2. ComponentReturn: replace El extends Element ? El : null with
   El extends null ? unknown : El. The old Element check deferred for
   conditional types; the new null check doesn't because null is concrete.

Based on draft PR typed-ember#613 by @gossi.
@johanrd
Copy link
Contributor

johanrd commented Mar 15, 2026

@gossi @wagenet: this should now be resolved in the latest release of glint. Please have a look to see if your use cases agree! thanks,

@gossi gossi closed this Mar 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants