Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 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 | 6x 6x 61x 61x 57x 247x 240x 61x 6x 96x 96x 17x 79x 19x 80x 80x 60x 6x 57x 6x 1x | /**
* This module is not part of the public API!
*/
/* API Barrier */
import { strict as assert } from 'assert';
/**
* Type that consists of the union of all properties that are marked as optional through a question mark.
*
* Note that properties that have undefined in their domain, but no question mark next to the property name are *not*
* included. Also note that, in strict compilation mode, TypeScript will add undefined to the domain of the property if
* there is a question mark next to the property name.
*
* @typeparam T generic type parameter
*/
export type OptionalPropertyNames<T extends {}> = {[K in keyof T]-?: {} extends {[_ in K]: T[K]} ? K : never}[keyof T];
export type Defined<T> = T extends undefined ? never : T;
export type OnlyOptionals<T extends {}> = {[K in OptionalPropertyNames<T>]: Defined<T[K]>};
/**
* Copy the values of all string-keyed enumerable own properties from the source object to the target object.
*
* Note the differences to
* [`Object.assign()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign):
* - Only properties with `string` keys are copied.
* - A property of the source value that has the value `undefined` is copied only if the property key is not yet in the
* target. (The check is performed using the `in` operator.)
*
* @param target the target object
* @param source the source object
* @return the target object
*/
export function assignDefined<T extends {[key: string]: any}, U extends {[key: string]: any}>(
target: T, source: U | undefined): T & U {
const typedTarget: T & U = target as T & U;
if (source !== undefined) {
// Object.entries() returns “a given object's own enumerable string-keyed property [key, value] pairs,”
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries
for (const [key, value] of Object.entries(source)) {
if (!(key in target) || value !== undefined) {
// Casting of key necessary for type soundness:
// https://github.com/microsoft/TypeScript/issues/31661#issuecomment-497474815
typedTarget[key as keyof U] = source[key];
}
}
}
return typedTarget;
}
/**
* Returns a deep clone of the given object.
*
* This function covers only what is needed in this project! It is not an equivalent to a library function.
*/
export function deepClone<T>(original: T): T {
assert(['undefined', 'object', 'boolean', 'number', 'string'].includes(typeof original),
'Value with unsupported type in deepClone()');
if (Array.isArray(original)) {
return original.map(deepClone) as T & any[];
} else if (typeof original === 'object' && original !== null) {
return Object.entries(original).reduce((obj, [key, value]) => {
// Casting of key necessary for type soundness:
// https://github.com/microsoft/TypeScript/issues/31661#issuecomment-497474815
obj[key as keyof T] = deepClone(value);
return obj;
}, {} as T & {[key: string]: any});
} else {
return original;
}
}
/**
* Returns the first argument that is defined, or undefined if none of the arguments is defined.
*/
export function coalesce<T>(left: T | undefined, right: T): T {
return left === undefined ? right : left;
}
/**
* Function that always throws an error.
*
* The purpose of this function is to be used as a compile-time type completeness check; for instance, in a `switch`
* statement. Calling this function will cause no error *only if* control-flow-based type analysis infers the argument
* type as `never` – in other words, if the function call cannot be reached.
*/
export function unreachableCase(x: never): never {
throw new Error(`Unexpected case that should be unreachable: ${x}`);
}
|