From 2f7de9d6f05bd7e463fdb63133a3c38dc2242614 Mon Sep 17 00:00:00 2001 From: Dan Freeman Date: Fri, 8 Apr 2022 15:04:36 +0200 Subject: [PATCH 1/3] Add missing `Params` layer to signature `Blocks` expansion --- packages/@glimmer/component/addon/-private/component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/@glimmer/component/addon/-private/component.ts b/packages/@glimmer/component/addon/-private/component.ts index d92fd1686..11e055e7f 100644 --- a/packages/@glimmer/component/addon/-private/component.ts +++ b/packages/@glimmer/component/addon/-private/component.ts @@ -62,8 +62,8 @@ type _ExpandSignature = { Blocks: T extends { Blocks: infer Blocks } ? { [Block in keyof Blocks]: Blocks[Block] extends unknown[] - ? { Positional: Blocks[Block] } - : Blocks[Block] + ? { Params: { Positional: Blocks[Block] } } + : Blocks[Block]; } : EmptyObject; }; From 2c03aae2abfbcedebd491af8512bc8651f0d3137 Mon Sep 17 00:00:00 2001 From: Dan Freeman Date: Fri, 8 Apr 2022 15:05:01 +0200 Subject: [PATCH 2/3] Add explicit types tests for `ExpandSignature` --- test/types/component-test.ts | 100 ++++++++++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/test/types/component-test.ts b/test/types/component-test.ts index 45a31630c..8841a4ceb 100644 --- a/test/types/component-test.ts +++ b/test/types/component-test.ts @@ -12,7 +12,10 @@ import Component from '@glimmer/component'; // matches the actual import location to which this type would be emitted. Since // this is an internal-only type whose presence consumers should not rely on and // which they should not use in any way, this is "safe" from a public API POV. -import { EmptyObject } from '@glimmer/component/dist/types/addon/-private/component'; +import { + EmptyObject, + ExpandSignature, +} from '@glimmer/component/dist/types/addon/-private/component'; declare let basicComponent: Component; expectTypeOf(basicComponent).toHaveProperty('args'); @@ -33,15 +36,37 @@ type LegacyArgs = { const componentWithLegacyArgs = new Component({}, { foo: 123 }); expectTypeOf(componentWithLegacyArgs.args).toEqualTypeOf>(); +expectTypeOf>().toEqualTypeOf<{ + Args: { Named: LegacyArgs; Positional: [] }; + Element: null; + Blocks: EmptyObject; +}>(); + // Here, we are testing that the types propertly distribute over union types, // generics which extend other types, etc. type LegacyArgsDistributive = { foo: number } | { bar: string; baz: boolean }; const legacyArgsDistributiveA = new Component({}, { foo: 123 }); expectTypeOf(legacyArgsDistributiveA.args).toEqualTypeOf>(); -const legacyArgsDistributiveB = new Component({}, { bar: "hello", baz: true }); +const legacyArgsDistributiveB = new Component( + {}, + { bar: 'hello', baz: true } +); expectTypeOf(legacyArgsDistributiveB.args).toEqualTypeOf>(); +expectTypeOf>().toEqualTypeOf< + | { + Args: { Named: { foo: number }; Positional: [] }; + Element: null; + Blocks: EmptyObject; + } + | { + Args: { Named: { bar: string; baz: boolean }; Positional: [] }; + Element: null; + Blocks: EmptyObject; + } +>(); + interface ExtensibleLegacy { value: T; extras: boolean; @@ -67,6 +92,12 @@ interface ArgsOnly { const componentWithArgsOnly = new Component({}, { foo: 123 }); expectTypeOf(componentWithArgsOnly.args).toEqualTypeOf>(); +expectTypeOf>().toEqualTypeOf<{ + Args: { Named: LegacyArgs; Positional: [] }; + Element: null; + Blocks: EmptyObject; +}>(); + interface ElementOnly { Element: HTMLParagraphElement; } @@ -75,6 +106,12 @@ const componentWithElOnly = new Component({}, {}); expectTypeOf(componentWithElOnly.args).toEqualTypeOf>(); +expectTypeOf>().toEqualTypeOf<{ + Args: { Named: EmptyObject; Positional: [] }; + Element: HTMLParagraphElement; + Blocks: EmptyObject; +}>(); + interface Blocks { default: [string]; inverse: []; @@ -88,6 +125,23 @@ const componentWithBlockOnly = new Component({}, {}); expectTypeOf(componentWithBlockOnly.args).toEqualTypeOf>(); +expectTypeOf>().toEqualTypeOf<{ + Args: { Named: EmptyObject; Positional: [] }; + Element: null; + Blocks: { + default: { + Params: { + Positional: [string]; + }; + }; + inverse: { + Params: { + Positional: []; + }; + }; + }; +}>(); + interface ArgsAndBlocks { Args: LegacyArgs; Blocks: Blocks; @@ -96,6 +150,23 @@ interface ArgsAndBlocks { const componentwithArgsAndBlocks = new Component({}, { foo: 123 }); expectTypeOf(componentwithArgsAndBlocks.args).toEqualTypeOf>(); +expectTypeOf>().toEqualTypeOf<{ + Args: { Named: LegacyArgs; Positional: [] }; + Element: null; + Blocks: { + default: { + Params: { + Positional: [string]; + }; + }; + inverse: { + Params: { + Positional: []; + }; + }; + }; +}>(); + interface ArgsAndEl { Args: LegacyArgs; Element: HTMLParagraphElement; @@ -104,6 +175,12 @@ interface ArgsAndEl { const componentwithArgsAndEl = new Component({}, { foo: 123 }); expectTypeOf(componentwithArgsAndEl.args).toEqualTypeOf>(); +expectTypeOf>().toEqualTypeOf<{ + Args: { Named: LegacyArgs; Positional: [] }; + Element: HTMLParagraphElement; + Blocks: EmptyObject; +}>(); + interface FullShortSig { Args: LegacyArgs; Element: HTMLParagraphElement; @@ -113,6 +190,23 @@ interface FullShortSig { const componentWithFullShortSig = new Component({}, { foo: 123 }); expectTypeOf(componentWithFullShortSig.args).toEqualTypeOf>(); +expectTypeOf>().toEqualTypeOf<{ + Args: { Named: LegacyArgs; Positional: [] }; + Element: HTMLParagraphElement; + Blocks: { + default: { + Params: { + Positional: [string]; + }; + }; + inverse: { + Params: { + Positional: []; + }; + }; + }; +}>(); + interface FullLongSig { Args: { Named: LegacyArgs; @@ -130,3 +224,5 @@ interface FullLongSig { const componentWithFullSig = new Component({}, { foo: 123 }); expectTypeOf(componentWithFullSig.args).toEqualTypeOf>(); + +expectTypeOf>().toEqualTypeOf(); From f1c905c9d3284740968031e72c26d66f732abf94 Mon Sep 17 00:00:00 2001 From: Dan Freeman Date: Fri, 8 Apr 2022 16:41:46 +0200 Subject: [PATCH 3/3] Add `typesVersions` entry for consistent Signature import paths --- packages/@glimmer/component/package.json | 9 ++++++++- test/types/component-test.ts | 5 +---- test/types/tsconfig.json | 4 ++++ 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/@glimmer/component/package.json b/packages/@glimmer/component/package.json index e34d8b829..f5241e6b0 100644 --- a/packages/@glimmer/component/package.json +++ b/packages/@glimmer/component/package.json @@ -85,6 +85,13 @@ "qunit-dom": "^0.7.1", "typescript": "~3.5.3" }, + "typesVersions": { + "*": { + "-private/*": [ + "dist/types/addon/-private/*" + ] + } + }, "engines": { "node": "6.* || 8.* || >= 10.*" }, @@ -93,4 +100,4 @@ "defaultBlueprint": "install-glimmer-component", "main": "ember-addon-main.js" } -} \ No newline at end of file +} diff --git a/test/types/component-test.ts b/test/types/component-test.ts index 8841a4ceb..d2a52717f 100644 --- a/test/types/component-test.ts +++ b/test/types/component-test.ts @@ -12,10 +12,7 @@ import Component from '@glimmer/component'; // matches the actual import location to which this type would be emitted. Since // this is an internal-only type whose presence consumers should not rely on and // which they should not use in any way, this is "safe" from a public API POV. -import { - EmptyObject, - ExpandSignature, -} from '@glimmer/component/dist/types/addon/-private/component'; +import { EmptyObject, ExpandSignature } from '@glimmer/component/-private/component'; declare let basicComponent: Component; expectTypeOf(basicComponent).toHaveProperty('args'); diff --git a/test/types/tsconfig.json b/test/types/tsconfig.json index 151648d63..aae575c6c 100644 --- a/test/types/tsconfig.json +++ b/test/types/tsconfig.json @@ -31,6 +31,10 @@ "noEmit": true, "paths": { + "@glimmer/component/-private/*": [ + // This must match the `typesVersions` entry in `@glimmer/component`'s package.json + "../../dist/@glimmer/component/dist/types/addon/-private/*" + ], "@glimmer/*": ["../../dist/@glimmer/*"] } }