mobx-keystone
Version:
A MobX powered state management solution based on data trees with first class support for TypeScript, snapshots, patches and much more
114 lines (95 loc) • 2.79 kB
text/typescript
import type { O } from "ts-toolbelt"
import type { AnyDataModel } from "../dataModel/BaseDataModel"
import type { AnyModel } from "../model/BaseModel"
import type { ModelClass } from "../modelShared/BaseModelShared"
import type { IsOptionalValue } from "../utils/types"
// type schemas
// infer is there just to cache type generation
export interface Type<Name, Data> {
/** @ignore */
$$type: Name
/** @ignore */
$$data: Data
}
export interface IdentityType<Data> extends Type<"identity", Data> {}
export interface ModelType<Model> extends Type<"model", Model> {}
export interface ArrayType<S> // e.g. S = someType[] or [someType, someType]
extends Type<
"array",
{
[k in keyof S]: TypeToData<S[k]> extends infer R ? R : never
}
> {}
export interface ObjectOfTypes {
/** @ignore */
[k: string]: AnyType
}
/**
* Name of the properties of an object that can be set to undefined, any or unknown
*/
type UndefinablePropsNames<T> = {
[K in keyof T]: IsOptionalValue<T[K], K, never>
}[keyof T]
export interface ObjectType<S>
extends Type<
"object",
O.Optional<
{ [k in keyof S]: TypeToData<S[k]> extends infer R ? R : never },
UndefinablePropsNames<{ [k in keyof S]: TypeToDataOpt<S[k]> extends infer R ? R : never }>
>
> {}
export interface ObjectTypeFunction {
// biome-ignore lint/style/useShorthandFunctionType: make the type recursive
(): ObjectOfTypes
}
export interface RecordType<S>
extends Type<
"record",
{
[k: string]: TypeToData<S> extends infer R ? R : never
}
> {}
export type AnyStandardType =
| IdentityType<any>
| ModelType<any>
| ArrayType<any>
| ObjectType<any>
| RecordType<any>
| ObjectTypeFunction
export type AnyType = null | undefined | AnyNonValueType
export type AnyNonValueType =
| ModelClass<AnyModel>
| ModelClass<AnyDataModel>
| StringConstructor
| NumberConstructor
| BooleanConstructor
| AnyStandardType
// type schemas to actual types
export type TypeToData<S> = S extends ObjectTypeFunction
? ObjectType<ReturnType<S>>["$$data"] extends infer R
? R
: never
: S extends { $$data: infer D }
? D
: // AnyModel
S extends ModelClass<infer M>
? M
: // String
S extends StringConstructor
? string
: // Number
S extends NumberConstructor
? number
: // Boolean
S extends BooleanConstructor
? boolean
: // null
S extends null
? null
: // undefined
S extends undefined
? undefined
: // anything else
never
/** @ignore */
export type TypeToDataOpt<S> = S extends { $$data: infer D } ? D & undefined : never