/** * @license * Copyright 2022-2026 Matter.js Authors * SPDX-License-Identifier: Apache-2.0 */ export type Properties = { [key: string]: any }; /** Merges two types into one. */ export type Merge = { [K in keyof A as K extends keyof B ? never : K]: A[K]; } & B; export function Merge(a: A, b: B): Merge { return { ...a, ...b }; } /** Type that represents a class constructor of a defined type or extend of it */ export type ClassExtends = { new (...args: any[]): C }; /** Merge an array of objects into one. Currently assumes unique elements */ export type MergeAll = T extends [infer O extends Properties | undefined, ...infer R] ? O extends undefined ? MergeAll : O & MergeAll : T extends [] ? {} : never; export function MergeAll(...objects: readonly [...T]): MergeAll { return Object.assign({}, ...objects); } /** Pluck an item from an array of objects if present */ export type Pluck = T extends [infer O, ...infer R] ? K extends keyof O ? [O[K], ...Pluck] : Pluck : T extends [] ? T : never; export function Pluck( key: K, ...objects: readonly [...T] ): Pluck { return objects.map(o => (o as any)[key]).filter(o => o !== undefined) as any; } /** Same as "a == undefined" but keeps the kids happy */ export function isNullish(a: any) { return a === undefined || a === null; } export type MakeMandatory = Exclude; /** Create a branded type */ declare const __brand: unique symbol; // Don't think it should be necessary to export Brand but it will cause // the following error under some circumstances: // // Exported variable 'XXX' has or is using name '__brand' from external // module "../src/util/Type" but cannot be named.ts(4023) // // Specifically this occurs with the reference to Cluster.id in the "complete" // cluster definitions export type Brand = { [__brand]: B }; export type Branded = T & Brand; /** * Make a type immutable. * * TODO - might need to extend depending type (e.g. doesn't handle Maps, Sets or Promises yet) * * Good reference implementation here: * * https://github.com/ts-essentials/ts-essentials/blob/master/lib/deep-readonly/index.ts */ export type Immutable = T extends (...args: any[]) => any ? T : T extends number // Necessary for our "branded" IDs ? T : T extends bigint ? T : T extends object ? { readonly [K in keyof T]: Immutable } : T; export type Mutable = T extends (...args: any[]) => any ? T : T extends number // Necessary for our "branded" IDs ? T : T extends bigint ? T : T extends object ? { -readonly [K in keyof T]: Mutable } : T; export function Mutable(value: Immutable): Mutable { return value as Mutable; } /** * Convert a union to an interface. * * @see {@link https://stackoverflow.com/questions/50374908} */ export type UnionToIntersection = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never; /** * An identity type. * * You can't do: * * interface Foo extends typeof Bar {} * * But you can do: * * interface Foo extends Identity {} * * Without this type you'd have to do: * * interface FooType = typeof Bar; * interface Foo extends FooType {}; * * We have to do this a lot because we generate complex objects with detailed * type information. When exported, TS (as of 5.2) inlines the type of these * objects in declarations which makes our declarations massive. To avoid this * we create an interface from the type then cast to the interface for export. */ export type Identity = T; /** * Tests whether the given variable is a real object and not an Array * @param it The variable to test * @returns true if it is Record */ export function isObject(it: unknown): it is Record { // This is necessary because: // typeof null === 'object' // typeof [] === 'object' // [] instanceof Object === true return Object.prototype.toString.call(it) === "[object Object]"; // this code is 25% faster than below one // return it && typeof it === 'object' && !(it instanceof Array); }