export type Optional = Pick, K & Omit> export type Only = { [P in keyof T]: T[P] } & { [P in keyof U]?: never } export type Either = Only | Only export interface Newable { new(...args: any[]): any } export type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array | BigInt64Array | BigUint64Array export type TypedArrayConstructor = Int8ArrayConstructor | Uint8ArrayConstructor | Uint8ClampedArrayConstructor | Int16ArrayConstructor | Uint16ArrayConstructor | Int32ArrayConstructor | Uint32ArrayConstructor | Float32ArrayConstructor | Float64ArrayConstructor | BigInt64ArrayConstructor | BigUint64ArrayConstructor export type PowersOfTwo = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824, 2147483648] export type PositiveInteger = `${T}` extends `-${string}` | '0' | `${string}.${string}` ? never : T export type CapitalizeAll> = T extends readonly [] ? [] : T extends readonly [infer Head extends string, ...infer Tail extends ReadonlyArray] ? [Capitalize, ...CapitalizeAll] : string[] export type Join, Sep extends string = ''> = T extends readonly [] ? '' : T extends readonly [infer Head] ? Head : T extends readonly [infer Head extends string, ...infer Tail extends ReadonlyArray] ? `${Head}${Sep}${Join}` : string export type Split = D extends '' ? [S] : S extends `${infer Head}${D}${infer Tail}` ? [Head, ...Split] : [S] export type PascalCaseFromDelimiter = S extends `${infer Left}${D}${infer Right}` ? `${PascalCaseFromDelimiter}${Capitalize>}` : S export type PascalCaseString = Capitalize, '-'>, '_'>, ' '>> export type PascalCase> = T extends string ? PascalCaseString : T extends ReadonlyArray ? Join, ''> : T export type IndexOf = T extends readonly [infer Head, ...infer Tail] ? Head extends V ? Acc['length'] : IndexOf : never export const uppercase = (s: T) => s.toUpperCase() as Uppercase export const lowercase = (s: T) => s.toLowerCase() as Lowercase export const split = (delim: D, s: T) => s.split(delim) as Split export const fromKebab = (s: T) => split('-', s) as Split export const toPascal = (xs: T) => uppercase(xs[0]) + xs.slice(1) as PascalCase const pascal = (xs: T) => xs.map(toPascal).join('') as PascalCase export const Enum = (...values: T[]) => Object.freeze( values.reduce((acc, x) => { const key = pascal(fromKebab(x)).toString() acc[key] = x return acc }, {}) ) as Readonly<{ [K in T as PascalCase]: K }> type ParseInt = T extends `${infer N extends number}` ? N : never type FlagEnum = Readonly<{ [K in keyof A as A[K] extends T ? PascalCase : never]: PowersOfTwo[ParseInt] }> export const FlagEnum = (...values: A) => Object.freeze( values.reduce((acc, x, i) => { const key = pascal(fromKebab(x)).toString() acc[key] = 1 << i return acc }, {}) ) as FlagEnum export const pick = (obj: T, ...keys: K[]): Pick => (Object.fromEntries( keys .filter(key => key in obj) .map(key => [key, obj[key]]) )) as Pick export const inclusivePick = (obj: T, ...keys: K[]) => Object.fromEntries( keys.map(key => [key, obj[key]]) ) as { [Key in K]: Key extends keyof T ? T[Key] : never } export const omit = (obj: T, ...keys: K[]) => Object.fromEntries( Object.entries(obj) .filter(([key]: K[]) => !keys.includes(key)) ) as Omit export class Flags { _value: number constructor(value: number) { this._value = value } static has(flag: number, bitflags: number) { return bitflags & flag } static add(a: number, b: number) { return a | b } has(flag: number) { return Flags.has(flag, this._value) } add(flag: number) { return Flags.add(flag, this._value) } }