@loopback/core
Version:
Define and implement core constructs such as Application and Component
61 lines (60 loc) • 2.19 kB
TypeScript
import { Constructor } from '@loopback/context';
/**
* A replacement for `typeof Target` to be used in mixin class definitions.
* This is a workaround for TypeScript limitation described in
* - https://github.com/microsoft/TypeScript/issues/17293
* - https://github.com/microsoft/TypeScript/issues/17744
* - https://github.com/microsoft/TypeScript/issues/36060
*
* @example
*
* ```ts
* export function MyMixin<T extends MixinTarget<Application>>(superClass: T) {
* return class extends superClass {
* // contribute new class members
* }
* };
* ```
*
* TypeScript does not allow class mixins to access protected members from
* the base class. You can use the following approach as a workaround:
*
* ```ts
* // eslint-disable-next-line @typescript-eslint/ban-ts-comment
* // @ts-ignore
* (this as unknown as {YourBaseClass}).protectedMember
* ```
*
* The directive `@ts-ignore` suppresses compiler error about accessing
* a protected member from outside. Unfortunately, it also disables other
* compile-time checks (e.g. to verify that a protected method was invoked
* with correct arguments, and so on). This is the same behavior you
* would get by using `Constructor<any>` instead of `MixinTarget<Application>`.
* The major improvement is that TypeScript can still infer the return
* type of the protected member, therefore `any` is NOT introduced to subsequent
* code.
*
* TypeScript also does not allow mixin class to overwrite a method inherited
* from a mapped type, see https://github.com/microsoft/TypeScript/issues/38496
* As a workaround, use `@ts-ignore` to disable the error.
*
* ```ts
* export function RepositoryMixin<T extends MixinTarget<Application>>(
* superClass: T,
* ) {
* return class extends superClass {
* // @ts-ignore
* public component<C extends Component = Component>(
* componentCtor: Constructor<C>,
* nameOrOptions?: string | BindingFromClassOptions,
* ) {
* const binding = super.component(componentCtor, nameOrOptions);
* // ...
* return binding;
* }
* }
* ```
*/
export type MixinTarget<T extends object> = Constructor<{
[P in keyof T]: T[P];
}>;