50 lines
1.8 KiB
TypeScript
50 lines
1.8 KiB
TypeScript
import { computed, Ref } from "vue";
|
|
import { isFunction } from "./common";
|
|
|
|
export const DoNotCache = Symbol("DoNotCache");
|
|
|
|
export type Computable<T> = T | Ref<T> | (() => T);
|
|
export type ProcessedComputable<T> = T | Ref<T>;
|
|
export type GetComputableType<T> = T extends { [DoNotCache]: true }
|
|
? T
|
|
: T extends () => infer S
|
|
? Ref<S>
|
|
: undefined extends T
|
|
? undefined
|
|
: T;
|
|
export type GetComputableTypeWithDefault<T, S> = undefined extends T
|
|
? S
|
|
: GetComputableType<NonNullable<T>>;
|
|
export type UnwrapComputableType<T> = T extends Ref<infer S> ? S : T extends () => infer S ? S : T;
|
|
|
|
export type ComputableKeysOf<T> = Pick<
|
|
T,
|
|
{
|
|
[K in keyof T]: T[K] extends Computable<unknown> ? K : never;
|
|
}[keyof T]
|
|
>;
|
|
|
|
// TODO fix the typing of this function, such that casting isn't necessary and can be used to
|
|
// detect if a createX function is validly written
|
|
export function processComputable<T, S extends keyof ComputableKeysOf<T>>(
|
|
obj: T,
|
|
key: S
|
|
): asserts obj is T & { [K in S]: ProcessedComputable<UnwrapComputableType<T[S]>> } {
|
|
const computable = obj[key];
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
if (isFunction(computable) && computable.length === 0 && !(computable as any)[DoNotCache]) {
|
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
// @ts-ignore
|
|
obj[key] = computed(computable.bind(obj));
|
|
}
|
|
}
|
|
|
|
export function convertComputable<T>(obj: Computable<T>): ProcessedComputable<T> {
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
if (isFunction(obj) && !(obj as any)[DoNotCache]) {
|
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
// @ts-ignore
|
|
obj = computed(obj);
|
|
}
|
|
return obj as ProcessedComputable<T>;
|
|
}
|