Skip to content

Commit

Permalink
add more constructor helpers for dealing also with abstract constructors
Browse files Browse the repository at this point in the history
  • Loading branch information
trusktr committed Nov 17, 2023
1 parent 6d66a45 commit 5d3d0d1
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 5 deletions.
6 changes: 5 additions & 1 deletion dist/utils.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ interface DescriptorWithOwner extends PropertyDescriptor {
export declare function getInheritedDescriptor<T extends object>(obj: T, key: keyof T): DescriptorWithOwner | undefined;
export declare function getInheritedPropertyNames<T extends object>(obj: T): (keyof T)[];
export type Constructor<T = object, A extends any[] = any[], Static = {}> = (new (...a: A) => T) & Static;
export declare function Constructor<T = object, Static = {}>(Ctor: Constructor<any>): Constructor<T> & Static;
export declare function Constructor<T = object, Static = {}>(Ctor: AnyConstructor<any>): Constructor<T> & Static;
export type AbstractConstructor<T = object, A extends any[] = any[], Static = {}> = (abstract new (...a: A) => T) & Static;
export declare function AbstractConstructor<T = object, Static = {}>(Ctor: AnyConstructor<any>): AbstractConstructor<T> & Static;
export type AnyConstructor<T = object, A extends any[] = any[], Static = {}> = Constructor<T, A, Static> | AbstractConstructor<T, A, Static>;
export declare function AnyConstructor<T = object, Static = {}>(Ctor: AnyConstructor<any>): AnyConstructor<T> & Static;
export declare function hasPrototype(obj: any, proto: any): boolean;
export declare function copyDescriptors(source: Object, destination: Object, mod?: any): void;
export declare function setDefaultPrototypeDescriptors(prototype: Object, { defaultClassDescriptor: { writable, enumerable, configurable } }: any): void;
Expand Down
2 changes: 1 addition & 1 deletion dist/utils.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions dist/utils.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/utils.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

68 changes: 66 additions & 2 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,13 +135,77 @@ export function getInheritedPropertyNames<T extends object>(obj: T): (keyof T)[]
return keys
}

/**
* Without type args, this is an easy shortcut for "any non-abstract constructor
* that has any args and returns any type of object".
*
* With type args, define a non-abstract constructor type that returns a certain
* instance type (optional), accepts certain args (optional, defaults to any
* args for simplicity in cases like class-factory mixins), and has certain
* static members (optional).
*/
export type Constructor<T = object, A extends any[] = any[], Static = {}> = (new (...a: A) => T) & Static

// this is used for type casting in special cases, see the declaration file
export function Constructor<T = object, Static = {}>(Ctor: Constructor<any>): Constructor<T> & Static {
/**
* Cast any constructor type (abstract or not) into a specific Constructor type.
* Useful for forcing type checks inside of mixins for example. This is unsafe:
* you can incorrectly cast one constructor into an unrelated constructor type,
* so use with care.
*/
export function Constructor<T = object, Static = {}>(Ctor: AnyConstructor<any>): Constructor<T> & Static {
return Ctor as unknown as Constructor<T> & Static
}

/**
* Without type args, this is an easy shortcut for "any abstract constructor
* that has any args and returns any type of object".
*
* With type args, define an abstract constructor type that returns a certain
* instance type (optional), accepts certain args (optional, defaults to any
* args for simplicity in cases like class-factory mixins), and has certain
* static members (optional).
*/
export type AbstractConstructor<T = object, A extends any[] = any[], Static = {}> = (abstract new (...a: A) => T) &
Static

/**
* Cast any constructor type (abstract or not) into a specific
* AbstractConstructor type. Useful for forcing type checks inside of mixins
* for example. This is unsafe: you can incorrectly cast one constructor into an
* unrelated constructor type, so use with care.
*/
export function AbstractConstructor<T = object, Static = {}>(
Ctor: AnyConstructor<any>,
): AbstractConstructor<T> & Static {
return Ctor as unknown as AbstractConstructor<T> & Static
}

/**
* Combines Constructor and AbstractConstructor to support assigning any type of
* constructor whether abstract or not.
*
* Without type args, this is an easy shortcut for "any constructor, abstract or not,
* that has any args and returns any type of object".
*
* With type args, define a constructor type (abstract or not) that returns a
* certain instance type (optional), accepts certain args (optional, defaults to
* any args for simplicity in cases like class-factory mixins), and has certain
* static members (optional).
*/
export type AnyConstructor<T = object, A extends any[] = any[], Static = {}> =
| Constructor<T, A, Static>
| AbstractConstructor<T, A, Static>

/**
* Cast any constructor type (abstract or not) into a specific
* AnyConstructor type. Useful for forcing type checks inside of mixins
* for example. This is unsafe: you can incorrectly cast one constructor into an
* unrelated constructor type, so use with care.
*/
export function AnyConstructor<T = object, Static = {}>(Ctor: AnyConstructor<any>): AnyConstructor<T> & Static {
return Ctor as unknown as AnyConstructor<T> & Static
}

// check if an object has the given prototype in its chain
export function hasPrototype(obj: any, proto: any) {
let currentProto = obj.__proto__
Expand Down

0 comments on commit 5d3d0d1

Please sign in to comment.