@glint/template 1.7.6 → 1.7.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,6 +7,7 @@ import {
7
7
  HasContext,
8
8
  InvokableInstance,
9
9
  TemplateContext,
10
+ Invokable,
10
11
  NamedArgs,
11
12
  } from '../integration';
12
13
  import {
@@ -15,6 +16,7 @@ import {
15
16
  MathMlElementForTagName,
16
17
  SVGElementForTagName,
17
18
  } from './types';
19
+ import { MaybeNamed, PrebindArgs, UnionKeysOf } from '../signature';
18
20
 
19
21
  /**
20
22
  * Used during emit to denote an object literal that corresponds
@@ -173,3 +175,32 @@ export declare function applyModifier(boundModifier: ModifierReturn): void;
173
175
  * syntax.
174
176
  */
175
177
  export declare function noop(value: unknown): void;
178
+
179
+ /*
180
+ * Pre-binds named args while preserving generic type parameters (#1068).
181
+ * Uses Args/T holistic capture instead of Named/Return decomposition.
182
+ * The keyword's old decomposing overloads validate arg types but erase T;
183
+ * this function preserves T but doesn't validate. The transform emits both
184
+ * via a comma expression so errors come from the keyword (mapped) and the
185
+ * result comes from here (T-preserving).
186
+ */
187
+ type BindNamedResult<Args, T, GivenNamed> =
188
+ // Named-only args (required or optional — handles double-currying)
189
+ Args extends [NamedArgs<infer Named>?]
190
+ ? (
191
+ ...named: MaybeNamed<PrebindArgs<NonNullable<Named>, keyof GivenNamed & UnionKeysOf<Named>>>
192
+ ) => T
193
+ : // Positional + named args
194
+ Args extends [...infer Positional, NamedArgs<infer Named>]
195
+ ? (
196
+ ...args: [
197
+ ...Positional,
198
+ ...MaybeNamed<PrebindArgs<NonNullable<Named>, keyof GivenNamed & UnionKeysOf<Named>>>,
199
+ ]
200
+ ) => T
201
+ : (...args: Args extends unknown[] ? Args : never) => T;
202
+
203
+ export declare function bindInvokable<Args extends unknown[], T, GivenNamed>(
204
+ invokable: (...args: Args) => T,
205
+ named: NamedArgs<GivenNamed>,
206
+ ): Invokable<BindNamedResult<Args, T, GivenNamed>>;
@@ -36,9 +36,14 @@ export type ModifierReturn = { [Modifier]: true };
36
36
  * Denotes that the associated entity may be invoked with the given
37
37
  * blocks, yielding params of the appropriate type.
38
38
  */
39
+ // The original conditional `El extends Element ? El : null` deferred for
40
+ // generic conditional types like `ElementFromTagName<T>` (#610). Replaced
41
+ // with `El extends null ? unknown : El` which only fires for literal null
42
+ // (not conditional types) and converts null → unknown for ComponentLike
43
+ // equivalence.
39
44
  export type ComponentReturn<BlockDefs, El = null> = {
40
45
  [Blocks]: BlockDefs;
41
- [Element]: El extends Element ? El : null;
46
+ [Element]: El extends null ? unknown : El;
42
47
  };
43
48
 
44
49
  /**
@@ -69,10 +74,14 @@ export interface NamedArgsMarker {
69
74
  [NamedArgs]: true;
70
75
  }
71
76
 
77
+ // Distributes so that a union type yields the keys of every constituent;
78
+ // plain `keyof` over a union only sees keys common to all constituents.
79
+ type KeysOfConstituents<T> = T extends unknown ? keyof T : never;
80
+
72
81
  export type NamedArgNames<T extends Invokable<AnyFunction>> =
73
82
  T extends Invokable<(...args: infer A) => any>
74
83
  ? A extends [...positional: infer _, named?: infer N]
75
- ? Exclude<keyof NonNullable<N>, typeof NamedArgs>
84
+ ? Exclude<KeysOfConstituents<NonNullable<N>>, typeof NamedArgs>
76
85
  : never
77
86
  : never;
78
87
 
@@ -1,5 +1,5 @@
1
- import { DirectInvokable, Invokable, NamedArgs, UnwrapNamedArgs } from '../integration';
2
- import { MaybeNamed, PrebindArgs, SliceFrom, SliceTo } from '../signature';
1
+ import { DirectInvokable, Invokable, NamedArgs } from '../integration';
2
+ import { MaybeNamed, PrebindArgs, SliceFrom, SliceTo, UnionKeysOf } from '../signature';
3
3
 
4
4
  type PrefixOf<T extends unknown[]> = T extends [arg: infer Arg, ...rest: infer Rest]
5
5
  ? [] | [Arg, ...PrefixOf<Rest>]
@@ -19,9 +19,7 @@ export type BindInvokableKeyword<Prefix extends number, Kind> = DirectInvokable<
19
19
  named: NamedArgs<Partial<Named> & GivenNamed>,
20
20
  ): Invokable<
21
21
  (
22
- ...named: MaybeNamed<
23
- PrebindArgs<NonNullable<Named>, keyof GivenNamed & keyof UnwrapNamedArgs<Named>>
24
- >
22
+ ...named: MaybeNamed<PrebindArgs<NonNullable<Named>, keyof GivenNamed & UnionKeysOf<Named>>>
25
23
  ) => Return
26
24
  >;
27
25
  <Named, Return extends Kind, GivenNamed>(
@@ -29,9 +27,7 @@ export type BindInvokableKeyword<Prefix extends number, Kind> = DirectInvokable<
29
27
  named: NamedArgs<Partial<Named> & GivenNamed>,
30
28
  ): null | Invokable<
31
29
  (
32
- ...named: MaybeNamed<
33
- PrebindArgs<NonNullable<Named>, keyof GivenNamed & keyof UnwrapNamedArgs<Named>>
34
- >
30
+ ...named: MaybeNamed<PrebindArgs<NonNullable<Named>, keyof GivenNamed & UnionKeysOf<Named>>>
35
31
  ) => Return
36
32
  >;
37
33
  // {{bind invokableWithNamedAndPositionalArgs name="foo"}}
@@ -42,9 +38,7 @@ export type BindInvokableKeyword<Prefix extends number, Kind> = DirectInvokable<
42
38
  (
43
39
  ...args: [
44
40
  ...Positional,
45
- ...MaybeNamed<
46
- PrebindArgs<NonNullable<Named>, keyof GivenNamed & keyof UnwrapNamedArgs<Named>>
47
- >,
41
+ ...MaybeNamed<PrebindArgs<NonNullable<Named>, keyof GivenNamed & UnionKeysOf<Named>>>,
48
42
  ]
49
43
  ) => Return
50
44
  >;
@@ -55,9 +49,7 @@ export type BindInvokableKeyword<Prefix extends number, Kind> = DirectInvokable<
55
49
  (
56
50
  ...args: [
57
51
  ...Positional,
58
- ...MaybeNamed<
59
- PrebindArgs<NonNullable<Named>, keyof GivenNamed & keyof UnwrapNamedArgs<Named>>
60
- >,
52
+ ...MaybeNamed<PrebindArgs<NonNullable<Named>, keyof GivenNamed & UnionKeysOf<Named>>>,
61
53
  ]
62
54
  ) => Return
63
55
  >;
@@ -44,23 +44,46 @@ export type ComponentSignatureBlocks<S> = S extends { Blocks: infer Blocks }
44
44
  : {};
45
45
 
46
46
  /** Given a component signature `S`, get back the `Element` type. */
47
+ // The original `NonNullable<Element> extends never` check deferred for generic
48
+ // conditional types like ElementFromTagName<T>, collapsing them to unknown
49
+ // (#610). Using `Element extends null` instead only fires for literal null
50
+ // (preserving null → unknown for ComponentLike equivalence) without breaking
51
+ // conditional types — TypeScript can verify the deferred result still extends
52
+ // Element because neither branch of ElementFromTagName<T> is null.
47
53
  export type ComponentSignatureElement<S> = S extends { Element: infer Element }
48
- ? NonNullable<Element> extends never
54
+ ? Element extends null
49
55
  ? unknown
50
56
  : Element
51
57
  : unknown;
52
58
 
53
- export type PrebindArgs<T, Args extends keyof UnwrapNamedArgs<T>> = NamedArgs<
54
- Omit<UnwrapNamedArgs<T>, Args> & Partial<Pick<UnwrapNamedArgs<T>, Args>>
59
+ // This distributes over union `T` so that each constituent only has the bound
60
+ // keys it actually declares omitted/made-optional. A non-distributive
61
+ // `Omit<A | B, ...>` would collapse the union to its common keys, losing the
62
+ // per-constituent shape (#1144).
63
+ export type PrebindArgs<T, Args extends UnionKeysOf<T>> = NamedArgs<
64
+ T extends any
65
+ ? Omit<UnwrapNamedArgs<T>, Args & keyof UnwrapNamedArgs<T>> &
66
+ Partial<Pick<UnwrapNamedArgs<T>, Args & keyof UnwrapNamedArgs<T>>>
67
+ : never
55
68
  >;
56
69
 
57
- export type MaybeNamed<T> = T extends any
58
- ? {} extends UnwrapNamedArgs<T>
59
- ? keyof UnwrapNamedArgs<T> extends never
70
+ // Keys across all constituents of a (possibly union) named-args type. Plain
71
+ // `keyof UnwrapNamedArgs<T>` would only see keys common to every constituent.
72
+ export type UnionKeysOf<T> = T extends any ? keyof UnwrapNamedArgs<T> : never;
73
+
74
+ // Note: this must produce a single parameter tuple rather than distributing a
75
+ // union `T` into a union of tuples. A union of tuples breaks contravariant
76
+ // assignability against the `(named: NamedArgs<Named>)` patterns used by
77
+ // `{{component}}`/`{{helper}}`/`{{modifier}}` to pre-bind named args (#1144).
78
+ // The checks below are still union-aware: `{} extends A | B` holds when any
79
+ // constituent accepts an empty hash, and `UnionKeysOf` collects keys from all
80
+ // constituents.
81
+ export type MaybeNamed<T> =
82
+ {} extends UnwrapNamedArgs<T>
83
+ ? [UnionKeysOf<T>] extends [never]
60
84
  ? []
61
85
  : [named?: T]
62
- : [named: T]
63
- : never;
86
+ : [named: T];
64
87
 
65
88
  export type Get<T, K, Otherwise = unknown> = K extends keyof T ? T[K] : Otherwise;
66
89
  export type Constrain<T, Constraint, Otherwise = Constraint> = T extends Constraint ? T : Otherwise;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glint/template",
3
- "version": "1.7.6",
3
+ "version": "1.7.8",
4
4
  "repository": "typed-ember/glint",
5
5
  "description": "Type definitions to back typechecking for Glimmer templates",
6
6
  "license": "MIT",