diff --git a/src/type/record/record.ts b/src/type/record/record.ts index edc436441..88e0d6ab2 100644 --- a/src/type/record/record.ts +++ b/src/type/record/record.ts @@ -46,139 +46,142 @@ import { CloneType } from '../clone/type' import { IsUndefined } from '../guard/value' import { TUnion as IsUnionType, TTemplateLiteral as IsTemplateLiteralType, TLiteral as IsLiteralType, TString as IsStringType, TInteger as IsIntegerType, TNumber as IsNumberType } from '../guard/type' +// ---------------------------------------------------------------- +// FromKeys +// ---------------------------------------------------------------- // prettier-ignore -export namespace RecordResolver { - // ---------------------------------------------------------------- - // FromKeys - // ---------------------------------------------------------------- - function FromPattern(pattern: string, T: TSchema) { - return { [Symbols.Kind]: 'Record', type: 'object', patternProperties: { [pattern]: CloneType(T) } } - } - function FromKeys(keys: string[], T: TSchema) { - const properties = keys.reduce((acc, key) => ({ ...acc, [key]: CloneType(T) }), {} as TProperties) - return Object(properties, { [Symbols.Hint]: 'Record' }) - } - // ---------------------------------------------------------------- - // FromTemplateLiteralKey (Fast Inference) - // ---------------------------------------------------------------- - export type FromTemplateLiteralKeyInfinite<_ extends TTemplateLiteral, T extends TSchema> = Ensure> - // prettier-ignore - export type FromTemplateLiteralKeyFinite> = ( - Ensure>> - ) - // prettier-ignore - export type FromTemplateLiteralKey = IsTemplateLiteralFinite extends false - ? FromTemplateLiteralKeyInfinite - : FromTemplateLiteralKeyFinite - // prettier-ignore - export function FromTemplateLiteralKey(K: K, T: T): FromTemplateLiteralKey { - const expression = TemplateLiteralParseExact(K.pattern) - return ( - IsTemplateLiteralFinite(expression) - ? FromKeys(IndexedKeyResolve(K), T) - : FromPattern(K.pattern, T) - ) as FromTemplateLiteralKey - } - // ---------------------------------------------------------------- - // FromEnumKey (Special Case) - // ---------------------------------------------------------------- - export type FromEnumKey, T extends TSchema> = Ensure> - // ---------------------------------------------------------------- - // FromUnionKey - // ---------------------------------------------------------------- - // prettier-ignore - export type FromUnionKeyLiteralString, T extends TSchema> = { [_ in K['const']]: T } - // prettier-ignore - export type FromUnionKeyLiteralNumber, T extends TSchema> = { [_ in K['const']]: T } - // prettier-ignore - export type FromUnionKeyRest = - K extends [infer L extends TSchema, ...infer R extends TSchema[]] ? ( - L extends TUnion ? FromUnionKeyRest & FromUnionKeyRest : - L extends TLiteral ? FromUnionKeyLiteralString & FromUnionKeyRest : - L extends TLiteral ? FromUnionKeyLiteralNumber & FromUnionKeyRest : - {}) : {} - // prettier-ignore - export type FromUnionKey> = ( - Ensure> - ) - // prettier-ignore - export function FromUnionKey(K: K, T: T): FromUnionKey { - return FromKeys(IndexedKeyResolve(Union(K)), T) as FromUnionKey - } - // ---------------------------------------------------------------- - // FromLiteralKey - // ---------------------------------------------------------------- - // prettier-ignore - export type FromLiteralKey = ( - Ensure]: T }>> - ) - // prettier-ignore - export function FromLiteralKey(K: K, T: T): FromLiteralKey { - return FromKeys([K.toString()], T) as FromLiteralKey - } - // ---------------------------------------------------------------- - // FromStringKey - // ---------------------------------------------------------------- - // prettier-ignore - export type FromStringKey<_ extends TString, T extends TSchema> = ( - TRecord - ) - // prettier-ignore - export function FromStringKey(K: K, T: T): FromStringKey { - const pattern = IsUndefined(K.pattern) ? PatternStringExact : K.pattern - return FromPattern(pattern, T) as FromStringKey - } - // ---------------------------------------------------------------- - // FromIntegerKey - // ---------------------------------------------------------------- - // prettier-ignore - export type FromIntegerKey<_ extends TSchema, T extends TSchema> = ( - TRecord - ) - // prettier-ignore - export function FromIntegerKey(_: K, T: T): FromIntegerKey { - return FromPattern(PatternNumberExact, T) as FromIntegerKey - } - // ---------------------------------------------------------------- - // FromNumberKey - // ---------------------------------------------------------------- - // prettier-ignore - export type FromNumberKey<_ extends TSchema, T extends TSchema> = ( - TRecord - ) - // prettier-ignore - export function FromNumberKey(_: K, T: T): FromIntegerKey { - return FromPattern(PatternNumberExact, T) as FromIntegerKey - } - // ---------------------------------------------------------------- - // Resolve - // ---------------------------------------------------------------- - // prettier-ignore - export type Resolve = - K extends TEnum ? FromEnumKey : // (Special: Ensure resolve Enum before Union) - K extends TUnion ? FromUnionKey : - K extends TTemplateLiteral ? FromTemplateLiteralKey : - K extends TLiteral ? FromLiteralKey : - K extends TInteger ? FromIntegerKey : - K extends TNumber ? FromNumberKey : - K extends TString ? FromStringKey : - TNever - // prettier-ignore - export function Resolve(K: K, T: T): Resolve { - return ( - IsUnionType(K) ? FromUnionKey(K.anyOf, T) : - IsTemplateLiteralType(K) ? FromTemplateLiteralKey(K, T) : - IsLiteralType(K) ? FromLiteralKey(K.const, T) : - IsStringType(K) ? FromStringKey(K, T) : - IsIntegerType(K) ? FromIntegerKey(K, T) : - IsNumberType(K) ? FromNumberKey(K, T) : - Never() - ) as unknown as Resolve - } +function FromPattern(pattern: string, T: TSchema) { + return { [Symbols.Kind]: 'Record', type: 'object', patternProperties: { [pattern]: CloneType(T) } } } +// prettier-ignore +function FromKeys(keys: string[], T: TSchema) { + const properties = keys.reduce((acc, key) => ({ ...acc, [key]: CloneType(T) }), {} as TProperties) + return Object(properties, { [Symbols.Hint]: 'Record' }) +} +// ---------------------------------------------------------------- +// FromTemplateLiteralKey (Fast Inference) +// ---------------------------------------------------------------- +// prettier-ignore +export type FromTemplateLiteralKeyInfinite<_ extends TTemplateLiteral, T extends TSchema> = Ensure> +// prettier-ignore +export type FromTemplateLiteralKeyFinite> = ( + Ensure>> +) +// prettier-ignore +export type FromTemplateLiteralKey = IsTemplateLiteralFinite extends false + ? FromTemplateLiteralKeyInfinite + : FromTemplateLiteralKeyFinite +// prettier-ignore +export function FromTemplateLiteralKey(K: K, T: T): FromTemplateLiteralKey { + const expression = TemplateLiteralParseExact(K.pattern) + return ( + IsTemplateLiteralFinite(expression) + ? FromKeys(IndexedKeyResolve(K), T) + : FromPattern(K.pattern, T) + ) as FromTemplateLiteralKey +} +// ---------------------------------------------------------------- +// FromEnumKey (Special Case) +// ---------------------------------------------------------------- +// prettier-ignore +export type FromEnumKey, T extends TSchema> = Ensure> +// ---------------------------------------------------------------- +// FromUnionKey +// ---------------------------------------------------------------- +// prettier-ignore +export type FromUnionKeyLiteralString, T extends TSchema> = { [_ in K['const']]: T } +// prettier-ignore +export type FromUnionKeyLiteralNumber, T extends TSchema> = { [_ in K['const']]: T } +// prettier-ignore +export type FromUnionKeyRest = + K extends [infer L extends TSchema, ...infer R extends TSchema[]] ? ( + L extends TUnion ? FromUnionKeyRest & FromUnionKeyRest : + L extends TLiteral ? FromUnionKeyLiteralString & FromUnionKeyRest : + L extends TLiteral ? FromUnionKeyLiteralNumber & FromUnionKeyRest : + {}) : {} +// prettier-ignore +export type FromUnionKey> = ( + Ensure> +) +// prettier-ignore +export function FromUnionKey(K: K, T: T): FromUnionKey { + return FromKeys(IndexedKeyResolve(Union(K)), T) as FromUnionKey +} +// ---------------------------------------------------------------- +// FromLiteralKey +// ---------------------------------------------------------------- +// prettier-ignore +export type FromLiteralKey = ( + Ensure]: T }>> +) +// prettier-ignore +export function FromLiteralKey(K: K, T: T): FromLiteralKey { + return FromKeys([K.toString()], T) as FromLiteralKey +} +// ---------------------------------------------------------------- +// FromStringKey +// ---------------------------------------------------------------- +// prettier-ignore +export type FromStringKey<_ extends TString, T extends TSchema> = ( + TRecord +) +// prettier-ignore +export function FromStringKey(K: K, T: T): FromStringKey { + const pattern = IsUndefined(K.pattern) ? PatternStringExact : K.pattern + return FromPattern(pattern, T) as FromStringKey +} +// ---------------------------------------------------------------- +// FromIntegerKey +// ---------------------------------------------------------------- +// prettier-ignore +export type FromIntegerKey<_ extends TSchema, T extends TSchema> = ( + TRecord +) +// prettier-ignore +export function FromIntegerKey(_: K, T: T): FromIntegerKey { + return FromPattern(PatternNumberExact, T) as FromIntegerKey +} +// ---------------------------------------------------------------- +// FromNumberKey +// ---------------------------------------------------------------- +// prettier-ignore +export type FromNumberKey<_ extends TSchema, T extends TSchema> = ( + TRecord +) +// prettier-ignore +export function FromNumberKey(_: K, T: T): FromIntegerKey { + return FromPattern(PatternNumberExact, T) as FromIntegerKey +} +// ---------------------------------------------------------------- +// Resolve +// ---------------------------------------------------------------- +// prettier-ignore +export type RecordResolve = + K extends TEnum ? FromEnumKey : // (Special: Ensure resolve Enum before Union) + K extends TUnion ? FromUnionKey : + K extends TTemplateLiteral ? FromTemplateLiteralKey : + K extends TLiteral ? FromLiteralKey : + K extends TInteger ? FromIntegerKey : + K extends TNumber ? FromNumberKey : + K extends TString ? FromStringKey : + TNever +// prettier-ignore +export function RecordResolve(K: K, T: T): RecordResolve { + return ( + IsUnionType(K) ? FromUnionKey(K.anyOf, T) : + IsTemplateLiteralType(K) ? FromTemplateLiteralKey(K, T) : + IsLiteralType(K) ? FromLiteralKey(K.const, T) : + IsStringType(K) ? FromStringKey(K, T) : + IsIntegerType(K) ? FromIntegerKey(K, T) : + IsNumberType(K) ? FromNumberKey(K, T) : + Never() + ) as unknown as RecordResolve +} + // ------------------------------------------------------------------ // TRecord // ------------------------------------------------------------------ +// prettier-ignore export interface TRecord extends TSchema { [Symbols.Kind]: 'Record' static: Record, string | number>, Static> @@ -186,7 +189,8 @@ export interface TRecord(K: K, T: T, options: ObjectOptions = {}): RecordResolver.Resolve { - return CloneType(RecordResolver.Resolve(K, T), options) +export function Record(K: K, T: T, options: ObjectOptions = {}): RecordResolve { + return CloneType(RecordResolve(K, T), options) }