Skip to content

Commit

Permalink
Add failing test for distributive signature types
Browse files Browse the repository at this point in the history
  • Loading branch information
chriskrycho committed Apr 1, 2022
1 parent 31ae962 commit 9c9f023
Showing 1 changed file with 49 additions and 21 deletions.
70 changes: 49 additions & 21 deletions test/types/component-test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { expectTypeOf } from 'expect-type';
import * as gc from '@glimmer/component';
import Component from '@glimmer/component';

// Imported from non-public-API so we can check that we are publishing what we
// expect to be -- and this keeps us honest about the fact that if we *change*
Expand All @@ -13,31 +14,58 @@ import * as gc from '@glimmer/component';
// 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';

const Component = gc.default;
declare let basicComponent: Component;
expectTypeOf(basicComponent).toHaveProperty('args');
expectTypeOf(basicComponent).toHaveProperty('isDestroying');
expectTypeOf(basicComponent).toHaveProperty('isDestroyed');
expectTypeOf(basicComponent).toHaveProperty('willDestroy');
expectTypeOf(basicComponent.isDestroying).toEqualTypeOf<boolean>();
expectTypeOf(basicComponent.isDestroyed).toEqualTypeOf<boolean>();
expectTypeOf(basicComponent.willDestroy).toEqualTypeOf<() => void>();

expectTypeOf(gc).toHaveProperty('default');
expectTypeOf(gc.default).toEqualTypeOf<typeof Component>();

type Args = {
type LegacyArgs = {
foo: number;
};

const componentWithLegacyArgs = new Component<Args>({}, { foo: 123 });
expectTypeOf(componentWithLegacyArgs).toHaveProperty('args');
expectTypeOf(componentWithLegacyArgs).toHaveProperty('isDestroying');
expectTypeOf(componentWithLegacyArgs).toHaveProperty('isDestroyed');
expectTypeOf(componentWithLegacyArgs).toHaveProperty('willDestroy');
expectTypeOf(componentWithLegacyArgs.args).toEqualTypeOf<Readonly<Args>>();
expectTypeOf(componentWithLegacyArgs.isDestroying).toEqualTypeOf<boolean>();
expectTypeOf(componentWithLegacyArgs.isDestroyed).toEqualTypeOf<boolean>();
expectTypeOf(componentWithLegacyArgs.willDestroy).toEqualTypeOf<() => void>();
const componentWithLegacyArgs = new Component<LegacyArgs>({}, { foo: 123 });
expectTypeOf(componentWithLegacyArgs.args).toEqualTypeOf<Readonly<LegacyArgs>>();

// 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<LegacyArgsDistributive>({}, { foo: 123 });
expectTypeOf(legacyArgsDistributiveA.args).toEqualTypeOf<Readonly<LegacyArgsDistributive>>();
const legacyArgsDistributiveB = new Component<LegacyArgsDistributive>({}, { bar: "hello", baz: true });
expectTypeOf(legacyArgsDistributiveB.args).toEqualTypeOf<Readonly<LegacyArgsDistributive>>();

interface ExtensibleLegacy<T> {
value: T;
extras: boolean;
funThings: string[];
}

class WithExtensibleLegacy<T extends ExtensibleLegacy<unknown>> extends Component<T> {}
declare const withExtensibleLegacy: WithExtensibleLegacy<ExtensibleLegacy<unknown>>;
expectTypeOf(withExtensibleLegacy.args.value).toEqualTypeOf<unknown>();
expectTypeOf(withExtensibleLegacy.args.extras).toEqualTypeOf<boolean>();
expectTypeOf(withExtensibleLegacy.args.funThings).toEqualTypeOf<string[]>();

interface Extended extends ExtensibleLegacy<string> {}

class WithExtensibleLegacySubclass extends WithExtensibleLegacy<Extended> {}
declare const withExtensibleLegacySubclass: WithExtensibleLegacySubclass;
expectTypeOf(withExtensibleLegacySubclass.args.value).toEqualTypeOf<string>();

interface ArgsOnly {
Args: Args;
Args: LegacyArgs;
}

const componentWithArgsOnly = new Component<ArgsOnly>({}, { foo: 123 });
expectTypeOf(componentWithArgsOnly.args).toEqualTypeOf<Readonly<Args>>();
expectTypeOf(componentWithArgsOnly.args).toEqualTypeOf<Readonly<LegacyArgs>>();

interface ElementOnly {
Element: HTMLParagraphElement;
Expand All @@ -61,33 +89,33 @@ const componentWithBlockOnly = new Component<BlockOnlySig>({}, {});
expectTypeOf(componentWithBlockOnly.args).toEqualTypeOf<Readonly<EmptyObject>>();

interface ArgsAndBlocks {
Args: Args;
Args: LegacyArgs;
Blocks: Blocks;
}

const componentwithArgsAndBlocks = new Component<ArgsAndBlocks>({}, { foo: 123 });
expectTypeOf(componentwithArgsAndBlocks.args).toEqualTypeOf<Readonly<Args>>();
expectTypeOf(componentwithArgsAndBlocks.args).toEqualTypeOf<Readonly<LegacyArgs>>();

interface ArgsAndEl {
Args: Args;
Args: LegacyArgs;
Element: HTMLParagraphElement;
}

const componentwithArgsAndEl = new Component<ArgsAndEl>({}, { foo: 123 });
expectTypeOf(componentwithArgsAndEl.args).toEqualTypeOf<Readonly<Args>>();
expectTypeOf(componentwithArgsAndEl.args).toEqualTypeOf<Readonly<LegacyArgs>>();

interface FullShortSig {
Args: Args;
Args: LegacyArgs;
Element: HTMLParagraphElement;
Blocks: Blocks;
}

const componentWithFullShortSig = new Component<FullShortSig>({}, { foo: 123 });
expectTypeOf(componentWithFullShortSig.args).toEqualTypeOf<Readonly<Args>>();
expectTypeOf(componentWithFullShortSig.args).toEqualTypeOf<Readonly<LegacyArgs>>();

interface FullLongSig {
Args: {
Named: Args;
Named: LegacyArgs;
Positional: [];
};
Element: HTMLParagraphElement;
Expand All @@ -101,4 +129,4 @@ interface FullLongSig {
}

const componentWithFullSig = new Component<FullLongSig>({}, { foo: 123 });
expectTypeOf(componentWithFullSig.args).toEqualTypeOf<Readonly<Args>>();
expectTypeOf(componentWithFullSig.args).toEqualTypeOf<Readonly<LegacyArgs>>();

0 comments on commit 9c9f023

Please sign in to comment.