UNPKG

mobx-keystone-mindreframer

Version:

A MobX powered state management solution based on data trees with first class support for Typescript, snapshots, patches and much more

75 lines (64 loc) 2.18 kB
import { lateVal } from "../utils" import { getTypeInfo } from "./getTypeInfo" import { resolveStandardType, resolveTypeChecker } from "./resolveTypeChecker" import type { AnyStandardType, AnyType } from "./schemas" import { lateTypeChecker, TypeChecker, TypeInfo, TypeInfoGen } from "./TypeChecker" import { TypeCheckError } from "./TypeCheckError" import { typesUnchecked } from "./unchecked" /** * A type that represents the union of several other types (a | b | c | ...). * * Example: * ```ts * const booleanOrNumberType = types.or(types.boolean, types.number) * ``` * * @typeparam T Type. * @param orTypes Possible types. * @returns */ export function typesOr<T extends AnyType[]>(...orTypes: T): T[number] { const typeInfoGen: TypeInfoGen = (t) => new OrTypeInfo(t, orTypes.map(resolveStandardType)) return lateTypeChecker(() => { const checkers = orTypes.map(resolveTypeChecker) // if the or includes unchecked then it is unchecked if (checkers.some((tc) => tc.unchecked)) { return typesUnchecked() as any } const getTypeName = (...recursiveTypeCheckers: TypeChecker[]) => { const typeNames = checkers.map((tc) => { if (recursiveTypeCheckers.includes(tc)) { return "..." } return tc.getTypeName(...recursiveTypeCheckers, tc) }) return typeNames.join(" | ") } const thisTc: TypeChecker = new TypeChecker( (value, path) => { const someMatchingType = checkers.some((tc) => !tc.check(value, path)) if (someMatchingType) { return null } else { return new TypeCheckError(path, getTypeName(thisTc), value) } }, getTypeName, typeInfoGen ) return thisTc }, typeInfoGen) as any } /** * `types.or` type info. */ export class OrTypeInfo extends TypeInfo { // memoize to always return the same array on the getter private _orTypeInfos = lateVal(() => this.orTypes.map(getTypeInfo)) get orTypeInfos(): ReadonlyArray<TypeInfo> { return this._orTypeInfos() } constructor(thisType: AnyStandardType, readonly orTypes: ReadonlyArray<AnyStandardType>) { super(thisType) } }