Skip to content

Commit

Permalink
Esm
Browse files Browse the repository at this point in the history
  • Loading branch information
sinclairzx81 committed Nov 28, 2023
1 parent e4e5335 commit 9105f7c
Showing 1 changed file with 134 additions and 130 deletions.
264 changes: 134 additions & 130 deletions src/type/record/record.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,147 +46,151 @@ 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<TRecord<TString, T>>
// prettier-ignore
export type FromTemplateLiteralKeyFinite<K extends TTemplateLiteral, T extends TSchema, I extends string = Static<K>> = (
Ensure<TObject<Evaluate<{ [_ in I]: T }>>>
)
// prettier-ignore
export type FromTemplateLiteralKey<K extends TTemplateLiteral, T extends TSchema> = IsTemplateLiteralFinite<K> extends false
? FromTemplateLiteralKeyInfinite<K, T>
: FromTemplateLiteralKeyFinite<K, T>
// prettier-ignore
export function FromTemplateLiteralKey<K extends TTemplateLiteral, T extends TSchema>(K: K, T: T): FromTemplateLiteralKey<K, T> {
const expression = TemplateLiteralParseExact(K.pattern)
return (
IsTemplateLiteralFinite(expression)
? FromKeys(IndexedKeyResolve(K), T)
: FromPattern(K.pattern, T)
) as FromTemplateLiteralKey<K, T>
}
// ----------------------------------------------------------------
// FromEnumKey (Special Case)
// ----------------------------------------------------------------
export type FromEnumKey<K extends Record<string, string | number>, T extends TSchema> = Ensure<TObject<{ [_ in K[keyof K]]: T }>>
// ----------------------------------------------------------------
// FromUnionKey
// ----------------------------------------------------------------
// prettier-ignore
export type FromUnionKeyLiteralString<K extends TLiteral<string>, T extends TSchema> = { [_ in K['const']]: T }
// prettier-ignore
export type FromUnionKeyLiteralNumber<K extends TLiteral<number>, T extends TSchema> = { [_ in K['const']]: T }
// prettier-ignore
export type FromUnionKeyRest<K extends TSchema[], T extends TSchema> =
K extends [infer L extends TSchema, ...infer R extends TSchema[]] ? (
L extends TUnion<infer S> ? FromUnionKeyRest<S, T> & FromUnionKeyRest<R, T> :
L extends TLiteral<string> ? FromUnionKeyLiteralString<L, T> & FromUnionKeyRest<R, T> :
L extends TLiteral<number> ? FromUnionKeyLiteralNumber<L, T> & FromUnionKeyRest<R, T> :
{}) : {}
// prettier-ignore
export type FromUnionKey<K extends TSchema[], T extends TSchema, P extends TProperties = FromUnionKeyRest<K, T>> = (
Ensure<TObject<P>>
)
// prettier-ignore
export function FromUnionKey<K extends TSchema[], T extends TSchema>(K: K, T: T): FromUnionKey<K, T> {
return FromKeys(IndexedKeyResolve(Union(K)), T) as FromUnionKey<K, T>
}
// ----------------------------------------------------------------
// FromLiteralKey
// ----------------------------------------------------------------
// prettier-ignore
export type FromLiteralKey<K extends TLiteralValue, T extends TSchema> = (
Ensure<TObject<{ [_ in Assert<K, PropertyKey>]: T }>>
)
// prettier-ignore
export function FromLiteralKey<K extends TLiteralValue, T extends TSchema>(K: K, T: T): FromLiteralKey<K, T> {
return FromKeys([K.toString()], T) as FromLiteralKey<K, T>
}
// ----------------------------------------------------------------
// FromStringKey
// ----------------------------------------------------------------
// prettier-ignore
export type FromStringKey<_ extends TString, T extends TSchema> = (
TRecord<TString, T>
)
// prettier-ignore
export function FromStringKey<K extends TString, T extends TSchema>(K: K, T: T): FromStringKey<K, T> {
const pattern = IsUndefined(K.pattern) ? PatternStringExact : K.pattern
return FromPattern(pattern, T) as FromStringKey<K, T>
}
// ----------------------------------------------------------------
// FromIntegerKey
// ----------------------------------------------------------------
// prettier-ignore
export type FromIntegerKey<_ extends TSchema, T extends TSchema> = (
TRecord<TNumber, T>
)
// prettier-ignore
export function FromIntegerKey<K extends TInteger, T extends TSchema>(_: K, T: T): FromIntegerKey<K, T> {
return FromPattern(PatternNumberExact, T) as FromIntegerKey<K, T>
}
// ----------------------------------------------------------------
// FromNumberKey
// ----------------------------------------------------------------
// prettier-ignore
export type FromNumberKey<_ extends TSchema, T extends TSchema> = (
TRecord<TNumber, T>
)
// prettier-ignore
export function FromNumberKey<K extends TNumber, T extends TSchema>(_: K, T: T): FromIntegerKey<K, T> {
return FromPattern(PatternNumberExact, T) as FromIntegerKey<K, T>
}
// ----------------------------------------------------------------
// Resolve
// ----------------------------------------------------------------
// prettier-ignore
export type Resolve<K extends TSchema, T extends TSchema> =
K extends TEnum<infer S> ? FromEnumKey<S, T> : // (Special: Ensure resolve Enum before Union)
K extends TUnion<infer S> ? FromUnionKey<S, T> :
K extends TTemplateLiteral ? FromTemplateLiteralKey<K, T> :
K extends TLiteral<infer S> ? FromLiteralKey<S, T> :
K extends TInteger ? FromIntegerKey<K, T> :
K extends TNumber ? FromNumberKey<K, T> :
K extends TString ? FromStringKey<K, T> :
TNever
// prettier-ignore
export function Resolve<K extends TSchema, T extends TSchema>(K: K, T: T): Resolve<K, T> {
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<K, T>
}
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<TRecord<TString, T>>
// prettier-ignore
export type FromTemplateLiteralKeyFinite<K extends TTemplateLiteral, T extends TSchema, I extends string = Static<K>> = (
Ensure<TObject<Evaluate<{ [_ in I]: T }>>>
)
// prettier-ignore
export type FromTemplateLiteralKey<K extends TTemplateLiteral, T extends TSchema> = IsTemplateLiteralFinite<K> extends false
? FromTemplateLiteralKeyInfinite<K, T>
: FromTemplateLiteralKeyFinite<K, T>
// prettier-ignore
export function FromTemplateLiteralKey<K extends TTemplateLiteral, T extends TSchema>(K: K, T: T): FromTemplateLiteralKey<K, T> {
const expression = TemplateLiteralParseExact(K.pattern)
return (
IsTemplateLiteralFinite(expression)
? FromKeys(IndexedKeyResolve(K), T)
: FromPattern(K.pattern, T)
) as FromTemplateLiteralKey<K, T>
}
// ----------------------------------------------------------------
// FromEnumKey (Special Case)
// ----------------------------------------------------------------
// prettier-ignore
export type FromEnumKey<K extends Record<string, string | number>, T extends TSchema> = Ensure<TObject<{ [_ in K[keyof K]]: T }>>
// ----------------------------------------------------------------
// FromUnionKey
// ----------------------------------------------------------------
// prettier-ignore
export type FromUnionKeyLiteralString<K extends TLiteral<string>, T extends TSchema> = { [_ in K['const']]: T }
// prettier-ignore
export type FromUnionKeyLiteralNumber<K extends TLiteral<number>, T extends TSchema> = { [_ in K['const']]: T }
// prettier-ignore
export type FromUnionKeyRest<K extends TSchema[], T extends TSchema> =
K extends [infer L extends TSchema, ...infer R extends TSchema[]] ? (
L extends TUnion<infer S> ? FromUnionKeyRest<S, T> & FromUnionKeyRest<R, T> :
L extends TLiteral<string> ? FromUnionKeyLiteralString<L, T> & FromUnionKeyRest<R, T> :
L extends TLiteral<number> ? FromUnionKeyLiteralNumber<L, T> & FromUnionKeyRest<R, T> :
{}) : {}
// prettier-ignore
export type FromUnionKey<K extends TSchema[], T extends TSchema, P extends TProperties = FromUnionKeyRest<K, T>> = (
Ensure<TObject<P>>
)
// prettier-ignore
export function FromUnionKey<K extends TSchema[], T extends TSchema>(K: K, T: T): FromUnionKey<K, T> {
return FromKeys(IndexedKeyResolve(Union(K)), T) as FromUnionKey<K, T>
}
// ----------------------------------------------------------------
// FromLiteralKey
// ----------------------------------------------------------------
// prettier-ignore
export type FromLiteralKey<K extends TLiteralValue, T extends TSchema> = (
Ensure<TObject<{ [_ in Assert<K, PropertyKey>]: T }>>
)
// prettier-ignore
export function FromLiteralKey<K extends TLiteralValue, T extends TSchema>(K: K, T: T): FromLiteralKey<K, T> {
return FromKeys([K.toString()], T) as FromLiteralKey<K, T>
}
// ----------------------------------------------------------------
// FromStringKey
// ----------------------------------------------------------------
// prettier-ignore
export type FromStringKey<_ extends TString, T extends TSchema> = (
TRecord<TString, T>
)
// prettier-ignore
export function FromStringKey<K extends TString, T extends TSchema>(K: K, T: T): FromStringKey<K, T> {
const pattern = IsUndefined(K.pattern) ? PatternStringExact : K.pattern
return FromPattern(pattern, T) as FromStringKey<K, T>
}
// ----------------------------------------------------------------
// FromIntegerKey
// ----------------------------------------------------------------
// prettier-ignore
export type FromIntegerKey<_ extends TSchema, T extends TSchema> = (
TRecord<TNumber, T>
)
// prettier-ignore
export function FromIntegerKey<K extends TInteger, T extends TSchema>(_: K, T: T): FromIntegerKey<K, T> {
return FromPattern(PatternNumberExact, T) as FromIntegerKey<K, T>
}
// ----------------------------------------------------------------
// FromNumberKey
// ----------------------------------------------------------------
// prettier-ignore
export type FromNumberKey<_ extends TSchema, T extends TSchema> = (
TRecord<TNumber, T>
)
// prettier-ignore
export function FromNumberKey<K extends TNumber, T extends TSchema>(_: K, T: T): FromIntegerKey<K, T> {
return FromPattern(PatternNumberExact, T) as FromIntegerKey<K, T>
}
// ----------------------------------------------------------------
// Resolve
// ----------------------------------------------------------------
// prettier-ignore
export type RecordResolve<K extends TSchema, T extends TSchema> =
K extends TEnum<infer S> ? FromEnumKey<S, T> : // (Special: Ensure resolve Enum before Union)
K extends TUnion<infer S> ? FromUnionKey<S, T> :
K extends TTemplateLiteral ? FromTemplateLiteralKey<K, T> :
K extends TLiteral<infer S> ? FromLiteralKey<S, T> :
K extends TInteger ? FromIntegerKey<K, T> :
K extends TNumber ? FromNumberKey<K, T> :
K extends TString ? FromStringKey<K, T> :
TNever
// prettier-ignore
export function RecordResolve<K extends TSchema, T extends TSchema>(K: K, T: T): RecordResolve<K, T> {
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<K, T>
}

// ------------------------------------------------------------------
// TRecord
// ------------------------------------------------------------------
// prettier-ignore
export interface TRecord<K extends TSchema = TSchema, T extends TSchema = TSchema> extends TSchema {
[Symbols.Kind]: 'Record'
static: Record<Assert<Static<K>, string | number>, Static<T, this['params']>>
type: 'object'
patternProperties: { [pattern: string]: T }
additionalProperties: TAdditionalProperties
}
// prettier-ignore
/** `[Json]` Creates a Record type */
export function Record<K extends TSchema, T extends TSchema>(K: K, T: T, options: ObjectOptions = {}): RecordResolver.Resolve<K, T> {
return CloneType(RecordResolver.Resolve(K, T), options)
export function Record<K extends TSchema, T extends TSchema>(K: K, T: T, options: ObjectOptions = {}): RecordResolve<K, T> {
return CloneType(RecordResolve(K, T), options)
}

0 comments on commit 9105f7c

Please sign in to comment.