You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

52 lines
1.1 KiB
TypeScript

export type Ref<T> = { __ref: keyof T };
export const ref = <T>(k: keyof T) => ({ __ref: k });
const isRef = <T>(t: unknown): t is Ref<T> =>
t !== null && typeof t === "object" && "__ref" in t;
export type Ouro<T> = {
[K in keyof T]: T[K] | Ref<T>
};
type Follow<T, K extends keyof T> =
T[K] extends Ref<T>
? Follow<T, T[K]["__ref"]>
: T[K];
export type Boros<T> = {
[K in keyof T]: Follow<T, K>
};
export const resolve = <T>(obj: Ouro<T>): Boros<T> => {
const newObj = {} as Partial<Boros<T>>;
const keysToProcess = new Set(Object.keys(obj) as (keyof typeof obj)[]);
while (true) {
if (keysToProcess.size === 0) {
break;
}
const keysToAssign = new Set<keyof T>();
let k = [...keysToProcess][0];
while (true) {
if (keysToAssign.has(k)) {
throw new Error("Infinite loop detected");
}
keysToProcess.delete(k);
keysToAssign.add(k);
const v = newObj[k] ?? obj[k];
if (!isRef<T>(v)) {
for (const k of keysToAssign) {
newObj[k] = v as Boros<T>[typeof k];
}
break;
}
k = v.__ref;
}
}
return newObj as Boros<T>;
};