import { IsStringLiteral, Split, IsNumericLiteral, IsSymbolLiteral, KeysOfUnion } from 'type-fest'; /** * Check if a type is guaranteed to be a bounded record: a record with a finite * set of keys. * * @example * IfBoundedRecord<{ a: 1, 1: "a" }>; //=> true * IfBoundedRecord>; //=> false * IfBoundedRecord>; //=> false */ type IfBoundedRecord = IsBoundedKey> extends true ? TypeIfBoundedRecord : TypeIfUnboundedRecord; /** * Checks if a type is a bounded key: a union of bounded strings, numeric * literals, or symbol literals. */ type IsBoundedKey = T extends unknown ? IsStringLiteral extends true ? IsBoundedString : IsNumericLiteral extends true ? true : IsSymbolLiteral : never; /** * Checks if a type is a bounded string: a type that only has a finite * number of strings that are that type. * * Most relevant for template literals: IsBoundedString<`${1 | 2}_${3 | 4}`> is * true, and IsBoundedString<`${1 | 2}_${number}`> is false. */ type IsBoundedString = T extends string ? Split[number] extends infer U ? [ `${number}` ] extends [U] ? false : [string] extends [U] ? false : true : false : false; export type { IfBoundedRecord as I };