Skip to content

Commit

Permalink
Merge pull request #20521 from littleredridingfox/types/controller-re…
Browse files Browse the repository at this point in the history
…gistry-fix

[FEATURE] Add TypeScript support for looking up controllers in DI registry
  • Loading branch information
chriskrycho authored Aug 11, 2023
2 parents 922480b + 8013003 commit a28a285
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 0 deletions.
26 changes: 26 additions & 0 deletions packages/@ember/controller/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -366,3 +366,29 @@ export function inject(
}

export { Controller as default, ControllerMixin };

/**
A type registry for Ember `Controller`s. Meant to be declaration-merged so string
lookups resolve to the correct type.
Blueprints should include such a declaration merge for TypeScript:
```ts
import Controller from '@ember/controller';
export default class ExampleController extends Controller {
// ...
}
declare module '@ember/controller' {
export interface Registry {
example: ExampleController;
}
}
```
Then `@inject` can check that the service is registered correctly, and APIs
like `owner.lookup('controller:example')` can return `ExampleController`.
*/
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface Registry extends Record<string, Controller | undefined> {}
11 changes: 11 additions & 0 deletions packages/@ember/controller/owner-ext.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// This module provides an 'extension' to the `@ember/owner` module from the
// `@ember/controller` module. Our type publishing infrastructure will pass it
// through unchanged, so end users will get this extension.

import type { Registry } from '@ember/controller';

declare module '@ember/owner' {
export interface DIRegistry {
controller: Registry;
}
}
11 changes: 11 additions & 0 deletions packages/@ember/controller/type-tests/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,14 @@ expectTypeOf(inject()).toMatchTypeOf<PropertyDecorator>();

// @ts-expect-error Doesn't allow invalid types
inject(1);

class ExampleController extends Controller {}

declare module '@ember/controller' {
export interface Registry {
example: ExampleController;
}
}

expectTypeOf(owner.lookup('controller:example')).toEqualTypeOf<ExampleController>();
expectTypeOf(owner.lookup('controller:non-registered')).toEqualTypeOf<Controller | undefined>();
8 changes: 8 additions & 0 deletions type-tests/@ember/controller-test/octane.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import Controller, { ControllerQueryParam, inject } from '@ember/controller';
import { expectTypeOf } from 'expect-type';
import type Owner from '@ember/owner';

class FirstController extends Controller {
foo = 'bar';
Expand Down Expand Up @@ -36,3 +38,9 @@ declare module '@ember/controller' {
second: InstanceType<typeof SecondController>;
}
}

const owner = {} as Owner;

expectTypeOf(owner.lookup('controller:first')).toEqualTypeOf<FirstController>();
expectTypeOf(owner.lookup('controller:second')).toEqualTypeOf<InstanceType<typeof SecondController>>();
expectTypeOf(owner.lookup('controller:non-registered')).toEqualTypeOf<Controller | undefined>();

0 comments on commit a28a285

Please sign in to comment.