UNPKG

2.19 kBTypeScriptView Raw
1import { Constructor } from '@loopback/context';
2/**
3 * A replacement for `typeof Target` to be used in mixin class definitions.
4 * This is a workaround for TypeScript limitation described in
5 * - https://github.com/microsoft/TypeScript/issues/17293
6 * - https://github.com/microsoft/TypeScript/issues/17744
7 * - https://github.com/microsoft/TypeScript/issues/36060
8 *
9 * @example
10 *
11 * ```ts
12 * export function MyMixin<T extends MixinTarget<Application>>(superClass: T) {
13 * return class extends superClass {
14 * // contribute new class members
15 * }
16 * };
17 * ```
18 *
19 * TypeScript does not allow class mixins to access protected members from
20 * the base class. You can use the following approach as a workaround:
21 *
22 * ```ts
23 * // eslint-disable-next-line @typescript-eslint/ban-ts-comment
24 * // @ts-ignore
25 * (this as unknown as {YourBaseClass}).protectedMember
26 * ```
27 *
28 * The directive `@ts-ignore` suppresses compiler error about accessing
29 * a protected member from outside. Unfortunately, it also disables other
30 * compile-time checks (e.g. to verify that a protected method was invoked
31 * with correct arguments, and so on). This is the same behavior you
32 * would get by using `Constructor<any>` instead of `MixinTarget<Application>`.
33 * The major improvement is that TypeScript can still infer the return
34 * type of the protected member, therefore `any` is NOT introduced to subsequent
35 * code.
36 *
37 * TypeScript also does not allow mixin class to overwrite a method inherited
38 * from a mapped type, see https://github.com/microsoft/TypeScript/issues/38496
39 * As a workaround, use `@ts-ignore` to disable the error.
40 *
41 * ```ts
42 * export function RepositoryMixin<T extends MixinTarget<Application>>(
43 * superClass: T,
44 * ) {
45 * return class extends superClass {
46 * // @ts-ignore
47 * public component<C extends Component = Component>(
48 * componentCtor: Constructor<C>,
49 * nameOrOptions?: string | BindingFromClassOptions,
50 * ) {
51 * const binding = super.component(componentCtor, nameOrOptions);
52 * // ...
53 * return binding;
54 * }
55 * }
56 * ```
57 */
58export type MixinTarget<T extends object> = Constructor<{
59 [P in keyof T]: T[P];
60}>;