UNPKG

mobx-keystone

Version:

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

90 lines (77 loc) 2.25 kB
import { computed } from "mobx" import { modelTypeKey } from "../model/metadata" import { Model } from "../model/Model" import type { ModelClass } from "../modelShared/BaseModelShared" import { typesString } from "../types/primitiveBased/typesPrimitive" import { tProp } from "../types/tProp" import { failure } from "../utils" /** * A reference model base type. * Use `customRef` to create a custom ref constructor. */ export abstract class Ref<T extends object> extends Model({ /** * Reference id. */ id: tProp(typesString), }) { protected abstract resolve(): T | undefined /** * The object this reference points to, or `undefined` if the reference is currently invalid. */ @computed get maybeCurrent(): T | undefined { return this.resolve() } /** * If the reference is currently valid. */ @computed get isValid(): boolean { return !!this.maybeCurrent } /** * The object this reference points to, or throws if invalid. */ @computed get current(): T { const current = this.maybeCurrent if (!current) { throw failure( `a reference of type '${this[modelTypeKey]}' could not resolve an object with id '${this.id}'` ) } return current } /** * Ensures back references for this ref are up to date. * This only needs to be called if you need to get the most up to date * back references while both still inside an action and while the reference * is not a child of the same root than the target. */ abstract forceUpdateBackRefs(): void } /** * @ignore */ export declare const customRefTypeSymbol: unique symbol /** A ref constructor for custom refs */ export interface RefConstructor<T extends object> { <TE extends T>(valueOrID: TE | string): Ref<TE> refClass: ModelClass<Ref<T>> [customRefTypeSymbol]: T // just for typings } /** * Checks if a ref object is of a given ref type. * * @template T Referenced object type. * @param ref Reference object. * @param refType Reference type. * @returns `true` if it is of the given type, false otherwise. */ export function isRefOfType<T extends object>( ref: Ref<object>, refType: RefConstructor<T> ): ref is Ref<T> { return ref instanceof refType.refClass }