Skip to content
This repository was archived by the owner on Oct 29, 2024. It is now read-only.

Commit 006323e

Browse files
committed
Fix type distributivity in Glimmer Component Signature
When using a `keyof` type to check whether the type parameter for Glimmer Component is a `Signature` or the classic `Args`-only type, if we do not force TS to distribute over union types, it resolves the `keyof` check for union types with no shared members as `never`, and `never extends <anything>` is always true. This in turn meant that for all such unions, as well as for cases where users were providing generic types which could then be further extended in their own subclasses. Accordingly, introduce the standard technique TypeScript provides for opting into distributivity: conditional types are documented to support exactly this. (cherry picked from commit ad429d5)
1 parent cccccd2 commit 006323e

File tree

1 file changed

+19
-12
lines changed

1 file changed

+19
-12
lines changed

packages/@glimmer/component/addon/-private/component.ts

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -60,18 +60,7 @@ type ArgsFor<S> = 'Args' extends keyof S
6060
: { Named: S['Args']; Positional: [] }
6161
: { Named: EmptyObject; Positional: [] };
6262

63-
/**
64-
* Given any allowed shorthand form of a signature, desugars it to its full
65-
* expanded type.
66-
*
67-
* @internal This is only exported so we can avoid duplicating it in
68-
* [Glint](https://github.com/typed-ember/glint) or other such tooling. It is
69-
* *not* intended for public usage, and the specific mechanics it uses may
70-
* change at any time. Although the signature produced by is part of Glimmer's
71-
* public API the existence and mechanics of this specific symbol are *not*,
72-
* so ***DO NOT RELY ON IT***.
73-
*/
74-
export type ExpandSignature<T> = {
63+
type _ExpandSignature<T> = {
7564
Element: GetOrElse<T, 'Element', null>;
7665
Args: keyof T extends 'Args' | 'Element' | 'Blocks' // Is this a `Signature`?
7766
? ArgsFor<T> // Then use `Signature` args
@@ -84,6 +73,24 @@ export type ExpandSignature<T> = {
8473
}
8574
: EmptyObject;
8675
};
76+
/**
77+
* Given any allowed shorthand form of a signature, desugars it to its full
78+
* expanded type.
79+
*
80+
* @internal This is only exported so we can avoid duplicating it in
81+
* [Glint](https://github.com/typed-ember/glint) or other such tooling. It is
82+
* *not* intended for public usage, and the specific mechanics it uses may
83+
* change at any time. Although the signature produced by is part of Glimmer's
84+
* public API the existence and mechanics of this specific symbol are *not*,
85+
* so ***DO NOT RELY ON IT***.
86+
*/
87+
// The conditional type here is because TS applies conditional types
88+
// distributively. This means that for union types, checks like `keyof T` get
89+
// all the keys from all elements of the union, instead of ending up as `never`
90+
// and then always falling into the `Signature` path instead of falling back to
91+
// the legacy args handling path.
92+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
93+
export type ExpandSignature<T> = T extends any ? _ExpandSignature<T> : never;
8794

8895
/**
8996
* @internal we use this type for convenience internally; inference means users

0 commit comments

Comments
 (0)