forked from inversify/monorepo
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(strongly-typed): inject decorator type
This change builds on the work of the [`TypedContainer`][1] by adding type definitions for a strongly-typed `inject` decorator. [1]: inversify#59
- Loading branch information
1 parent
207a5a5
commit e9c4823
Showing
5 changed files
with
167 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
export { TypedContainer } from './container'; | ||
export type { TypedInject } from './inject'; |
67 changes: 67 additions & 0 deletions
67
packages/container/libraries/strongly-typed/src/inject.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
/* eslint-disable @typescript-eslint/no-unused-expressions */ | ||
/* eslint-disable jest/expect-expect */ | ||
import { describe, it } from '@jest/globals'; | ||
|
||
import { inject, injectable } from 'inversify'; | ||
|
||
import type { TypedInject } from './inject'; | ||
|
||
describe('@inject', () => { | ||
@injectable() | ||
class Foo { | ||
public foo: string = ''; | ||
} | ||
|
||
@injectable() | ||
class Bar { | ||
public bar: string = ''; | ||
} | ||
|
||
interface BindingMap { | ||
foo: Foo; | ||
bar: Bar; | ||
asyncNumber: Promise<number>; | ||
} | ||
|
||
const $inject: TypedInject<BindingMap> = inject as TypedInject<BindingMap>; | ||
|
||
it('strongly types injected properties', () => { | ||
class Test { | ||
@$inject('foo') | ||
public foo!: Foo; | ||
|
||
@$inject('bar') | ||
public readonly bar!: Bar; | ||
|
||
// @ts-expect-error :: expects type Bar | ||
@$inject('foo') | ||
public badFoo!: Bar; | ||
|
||
// @ts-expect-error :: unknown binding | ||
@$inject('unknown') | ||
public unknown!: unknown; | ||
} | ||
Test; | ||
}); | ||
|
||
it('strongly types injected constructor parameters', () => { | ||
class Test { | ||
constructor( | ||
@$inject('foo') | ||
_foo: Foo, | ||
|
||
@$inject('bar') | ||
private readonly _bar: Bar, | ||
|
||
// @ts-expect-error :: expects type Bar | ||
@$inject('foo') | ||
_badFoo: Bar, | ||
|
||
// @ts-expect-error :: unknown binding | ||
@$inject('unknown') | ||
_unknown: unknown, | ||
) {} | ||
} | ||
Test; | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
import type { BindingMap } from './container'; | ||
|
||
type TypedDecorator<T> = <TTarget, TKey, TIndex>( | ||
target: TTarget extends new (...args: any[]) => any | ||
? TTarget | ||
: TKey extends keyof TTarget | ||
? Record<TKey, T> | ||
: never, | ||
key: TKey extends keyof TTarget ? TKey : PropertyKey | undefined, | ||
indexOrPropertyDescriptor?: TTarget extends new (...args: infer P) => any | ||
? TIndex extends keyof P | ||
? P[TIndex] extends T | ||
? TIndex | ||
: never | ||
: never | ||
: unknown, | ||
) => void; | ||
|
||
export type TypedInject<TBindingMap extends BindingMap> = < | ||
TKey extends keyof TBindingMap, | ||
>( | ||
identifier: TKey, | ||
) => TypedDecorator<TBindingMap[TKey]>; |