UNPKG

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