/
UtilityTypes.ts
145 lines (129 loc) · 6 KB
/
UtilityTypes.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
* @module Utils
*/
/** The inverse of TypeScript's Readonly<T> type, producing a type that has all the properties of `T` with any `readonly` modifiers removed.
* @public
*/
export type Mutable<T> = {
-readonly [K in keyof T]: T[K];
};
/** Make a new type from an existing type `T`, with set of required properties `K` optional.
* @public
*/
export type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;
/** Make a new type from an existing type `T`, with set of optional properties `K` required.
* @public
*/
export type MarkRequired<T, K extends keyof T> = Pick<Required<T>, K> & Omit<T, K>;
/** Generically represents a class `T`, for use in type annotations.
* @note A variable of type `Constructor<T>` matches a class `T` only if `T` has a **public** constructor.
* @see [[asInstanceOf]] to attempt to cast an arbitrary value to class `T`.
* @see [[isInstanceOf]] to determine if an arbitrary value is an instance of class `T`.
* @public
*/
export type Constructor<T> = new (...args: any[]) => T;
/** Returns true if `obj` is an object of class `T`.
* @see [[asInstanceOf]] to cast `obj` to class `T`.
* @public
*/
export function isInstanceOf<T>(obj: any, constructor: Constructor<T>): boolean {
return "object" === typeof obj && obj instanceof constructor;
}
/** Cast `obj` to an instance of class `T`, or return undefined if `obj` is not an instance of class `T`.
* @see [[isInstanceOf]] to query whether `obj` is of class `T`.
* @public
*/
export function asInstanceOf<T>(obj: any, constructor: Constructor<T>): T | undefined {
return isInstanceOf<T>(obj, constructor) ? obj as T : undefined;
}
/** Extracts the names of all public properties of `T` that are not of type `function`.
* This includes properties defined using `get` syntax. Care should be used when using this type in conjunction with
* the object spread (`...`) operator, because the spread operator omits properties defined using `get` syntax and, therefore,
* so too does the type that TypeScript infers from that operator.
* `get` syntax. For example:
* ```ts
* class Thing {
* private _a = "a"; // a private variable
* public b = "b"; // a public variable
* public get c() { return "c"; } // a public property
* public d() { return "d"; } // a public method
* public e = () => "e"; // a public variable of type `function`
* }
*
* // The following can have the values "b" or "c" - those are the public, non-function properties of Thing.
* let nonFunctionProperty: NonFunctionPropertyNamesOf<Thing> = "c";
*
* // The following produces an error: "Property 'c' is missing in type '{ b: string; e: () => string; }' but required in type 'NonFunctionPropertiesOf<Thing>'"
* const thing1 = new Thing();
* const thing2: NonFunctionPropertiesOf<Thing> = { ...thing1 };
* ```
* @see [[NonFunctionPropertiesOf]] to obtain a type that includes only these properties.
* @public
*/
export type NonFunctionPropertyNamesOf<T> = {
[K in keyof T]: T[K] extends Function ? never : K;
}[keyof T];
/** Produces a type consisting of all of the public properties of `T` except for those of type `function`.
* @see [[NonFunctionPropertyNamesOf]] for potential pitfalls when used in conjunction with the object spread operator.
* @public
*/
export type NonFunctionPropertiesOf<T> = Pick<T, NonFunctionPropertyNamesOf<T>>;
/** Any function returning a Promise.
* @see [[AsyncMethodsOf]] to extract all async methods from a type.
* @see [[PromiseReturnType]] to extract the type to which the Promise resolves.
* @public
*/
export type AsyncFunction = (...args: any[]) => Promise<unknown>;
/** The members of `T` that are async functions (functions that return a promise), and no other properties
* @public
*/
export type PickAsyncMethods<T> = { [P in keyof T]: T[P] extends AsyncFunction ? T[P] : never; };
/** Extracts the names of all function properties of `T` that return a Promise.
* @public
*/
export type AsyncMethodsOf<T> = { [P in keyof T]: T[P] extends AsyncFunction ? P : never }[keyof T];
/** Extracts the type to which the Promise returned by an async function resolves.
* @public
*/
export type PromiseReturnType<T extends AsyncFunction> = T extends (...args: any) => Promise<infer R> ? R : any;
/** The members of `T` that are functions and no other properties
* @public
*/
export type PickMethods<T> = { [P in keyof T]: T[P] extends Function ? T[P] : never; };
/** The members of `T` that are functions that do not return a Promise
* @public
*/
export type PickSyncMethods<T> = Omit<PickMethods<T>, AsyncMethodsOf<T>>;
/** A runtime property omitter, makes a shallow copy of the given object without the specified properties
* Compatible with the typescript `Omit` mapped type:
* ```js
* const testvar: Omit<{x: string, y: object}, "y"> = omit({x: "hello", y: {}}, ["y"]);
* ```
* @public
*/
export function omit<T extends {}, K extends readonly (keyof T)[]>(t: T, keys: K): Omit<T, K[number]> {
const clone = { ...t };
for (const key of keys)
delete clone[key];
return clone;
}
/** Defines a type wherein at least one of the properties of T is required to exist.
* In the following example, paying for a coffee requires a customer to have either a credit card, some cash, or both in their wallet.
* ```ts
* interface Wallet {
* cash?: number;
* card?: CreditCard;
* }
*
* function payForCoffee(wallet: RequireAtLeastOne<Wallet>) { ... }
* ```
* Source: [@azure/keyvault-certificates](https://learn.microsoft.com/en-us/javascript/api/@azure/keyvault-certificates/requireatleastone?view=azure-node-latest).
* @public
*/
export type RequireAtLeastOne<T> = {
[K in keyof T]-?: Required<Pick<T, K>> & Partial<Pick<T, Exclude<keyof T, K>>>;
}[keyof T];