diff options
author | bobzel <zzzman@gmail.com> | 2023-04-05 22:44:03 -0400 |
---|---|---|
committer | bobzel <zzzman@gmail.com> | 2023-04-05 22:44:03 -0400 |
commit | 9b41da1af16b982ee8ac2fc09f2f8b5d67eac9fb (patch) | |
tree | bc3f57cd5b31fd453d272c925f6d5b728ab63bae /src/fields/Types.ts | |
parent | 9dae453967183b294bf4f7444b948023a1d52d39 (diff) | |
parent | 8f7e99641f84ad15f34ba9e4a60b664ac93d2e5d (diff) |
Merge branch 'master' into data-visualization-view-naafi
Diffstat (limited to 'src/fields/Types.ts')
-rw-r--r-- | src/fields/Types.ts | 93 |
1 files changed, 50 insertions, 43 deletions
diff --git a/src/fields/Types.ts b/src/fields/Types.ts index bf40a0d7b..4cf286a32 100644 --- a/src/fields/Types.ts +++ b/src/fields/Types.ts @@ -1,48 +1,50 @@ -import { Field, Opt, FieldResult, Doc } from "./Doc"; -import { List } from "./List"; -import { RefField } from "./RefField"; -import { DateField } from "./DateField"; -import { ScriptField } from "./ScriptField"; -import { URLField, WebField, ImageField } from "./URLField"; -import { TextField } from "@material-ui/core"; -import { RichTextField } from "./RichTextField"; - -export type ToType<T extends InterfaceValue> = - T extends "string" ? string : - T extends "number" ? number : - T extends "boolean" ? boolean : - T extends ListSpec<infer U> ? List<U> : - // T extends { new(...args: any[]): infer R } ? (R | Promise<R>) : never; - T extends DefaultFieldConstructor<infer _U> ? never : - T extends { new(...args: any[]): List<Field> } ? never : - T extends { new(...args: any[]): infer R } ? R : - T extends (doc?: Doc) => infer R ? R : never; - -export type ToConstructor<T extends Field> = - T extends string ? "string" : - T extends number ? "number" : - T extends boolean ? "boolean" : - T extends List<infer U> ? ListSpec<U> : - new (...args: any[]) => T; +import { Field, Opt, FieldResult, Doc } from './Doc'; +import { List } from './List'; +import { RefField } from './RefField'; +import { DateField } from './DateField'; +import { ScriptField } from './ScriptField'; +import { URLField, WebField, ImageField } from './URLField'; +import { TextField } from '@material-ui/core'; +import { RichTextField } from './RichTextField'; + +export type ToType<T extends InterfaceValue> = T extends 'string' + ? string + : T extends 'number' + ? number + : T extends 'boolean' + ? boolean + : T extends ListSpec<infer U> + ? List<U> + : // T extends { new(...args: any[]): infer R } ? (R | Promise<R>) : never; + T extends DefaultFieldConstructor<infer _U> + ? never + : T extends { new (...args: any[]): List<Field> } + ? never + : T extends { new (...args: any[]): infer R } + ? R + : T extends (doc?: Doc) => infer R + ? R + : never; + +export type ToConstructor<T extends Field> = T extends string ? 'string' : T extends number ? 'number' : T extends boolean ? 'boolean' : T extends List<infer U> ? ListSpec<U> : new (...args: any[]) => T; export type ToInterface<T extends Interface> = { - [P in Exclude<keyof T, "proto">]: T[P] extends DefaultFieldConstructor<infer F> ? Exclude<FieldResult<F>, undefined> : FieldResult<ToType<T[P]>>; + [P in Exclude<keyof T, 'proto'>]: T[P] extends DefaultFieldConstructor<infer F> ? Exclude<FieldResult<F>, undefined> : FieldResult<ToType<T[P]>>; }; // type ListSpec<T extends Field[]> = { List: ToContructor<Head<T>> | ListSpec<Tail<T>> }; export type ListSpec<T extends Field> = { List: ToConstructor<T> }; export type DefaultFieldConstructor<T extends Field> = { - type: ToConstructor<T>, - defaultVal: T + type: ToConstructor<T>; + defaultVal: T; }; // type ListType<U extends Field[]> = { 0: List<ListType<Tail<U>>>, 1: ToType<Head<U>> }[HasTail<U> extends true ? 0 : 1]; export type Head<T extends any[]> = T extends [any, ...any[]] ? T[0] : never; -export type Tail<T extends any[]> = - ((...t: T) => any) extends ((_: any, ...tail: infer TT) => any) ? TT : []; -export type HasTail<T extends any[]> = T extends ([] | [any]) ? false : true; +export type Tail<T extends any[]> = ((...t: T) => any) extends (_: any, ...tail: infer TT) => any ? TT : []; +export type HasTail<T extends any[]> = T extends [] | [any] ? false : true; export type InterfaceValue = ToConstructor<Field> | ListSpec<Field> | DefaultFieldConstructor<Field> | ((doc?: Doc) => any); //TODO Allow you to optionally specify default values for schemas, which should then make that field not be partial @@ -58,14 +60,14 @@ export function Cast<T extends CastCtor>(field: FieldResult, ctor: T): FieldResu export function Cast<T extends CastCtor>(field: FieldResult, ctor: T, defaultVal: WithoutList<WithoutRefField<ToType<T>>> | null): WithoutList<ToType<T>>; export function Cast<T extends CastCtor>(field: FieldResult, ctor: T, defaultVal?: ToType<T> | null): FieldResult<ToType<T>> | undefined { if (field instanceof Promise) { - return defaultVal === undefined ? field.then(f => Cast(f, ctor) as any) as any : defaultVal === null ? undefined : defaultVal; + return defaultVal === undefined ? (field.then(f => Cast(f, ctor) as any) as any) : defaultVal === null ? undefined : defaultVal; } if (field !== undefined && !(field instanceof Promise)) { - if (typeof ctor === "string") { + if (typeof ctor === 'string') { if (typeof field === ctor) { return field as ToType<T>; } - } else if (typeof ctor === "object") { + } else if (typeof ctor === 'object') { if (field instanceof List) { return field as any; } @@ -77,19 +79,20 @@ export function Cast<T extends CastCtor>(field: FieldResult, ctor: T, defaultVal } export function DocCast(field: FieldResult, defaultVal?: Doc) { - return Cast(field, Doc, null) ?? defaultVal; + const doc = Cast(field, Doc, null); + return doc && !(doc instanceof Promise) ? doc : (defaultVal as Doc); } export function NumCast(field: FieldResult, defaultVal: number | null = 0) { - return Cast(field, "number", defaultVal); + return Cast(field, 'number', defaultVal); } -export function StrCast(field: FieldResult, defaultVal: string | null = "") { - return Cast(field, "string", defaultVal); +export function StrCast(field: FieldResult, defaultVal: string | null = '') { + return Cast(field, 'string', defaultVal); } export function BoolCast(field: FieldResult, defaultVal: boolean | null = false) { - return Cast(field, "boolean", defaultVal); + return Cast(field, 'boolean', defaultVal); } export function DateCast(field: FieldResult) { return Cast(field, DateField, null); @@ -113,7 +116,7 @@ type WithoutList<T extends Field> = T extends List<infer R> ? (R extends RefFiel export function FieldValue<T extends Field, U extends WithoutList<T>>(field: FieldResult<T>, defaultValue: U): WithoutList<T>; export function FieldValue<T extends Field>(field: FieldResult<T>): Opt<T>; export function FieldValue<T extends Field>(field: FieldResult<T>, defaultValue?: T): Opt<T> { - return (field instanceof Promise || field === undefined) ? defaultValue : field; + return field instanceof Promise || field === undefined ? defaultValue : field; } export interface PromiseLike<T> { @@ -121,5 +124,9 @@ export interface PromiseLike<T> { } export function PromiseValue<T extends Field>(field: FieldResult<T>): PromiseLike<Opt<T>> { if (field instanceof Promise) return field as Promise<Opt<T>>; - return { then(cb: ((field: Opt<T>) => void)) { return cb(field); } }; -}
\ No newline at end of file + return { + then(cb: (field: Opt<T>) => void) { + return cb(field); + }, + }; +} |