So we have like:
Dict
which is{ [key: string]: () => any }
X
which is the return I want
And I'm trying to create a type for a function that:
- receives a dictionary
Dict
T
- returns an
X
Now, X
is also a function, but this one:
- receives a
Dict
U
- returns itself (
X
) - we can access all the properties of
U
plus all the properties ofT
that aren't overwritten by properties ofU
- and the return value keeps reference of all the keys inside, so we can't access keys not defined in any of the previous chains
The function is bellow, any I'm not quite sure how to type it...
export function lazylet(values) {
const createStore = (overrides) => {
return lazylet({
...values,
...overrides,
});
};
Object.entries(values).map(([key, factory]) => {
Object.defineProperty(createStore, key, {
enumerable: true,
configurable: true,
get() {
const value = factory()
Object.defineProperty(createStore, key, { get: () => value });
return value;
},
})
});
return createStore;
};
An example of the use I'm looking for is something like this:
const laz1 = lazylet({ a: () => "hello", b: () => Math.random() })
/* const laz1: LazyLet<{
a: string;
b: number;
}> */
console.log(laz1.a.toUpperCase()) // "HELLO"
console.log(laz1.b.toFixed(2)) // "0.67" or something
console.log(laz1.b.toFixed(2)) // "0.67" same
const laz2 = laz1({ c: () => Math.random() < 0.5 });
/* const laz2: LazyLet<{
a: string;
b: number;
c: boolean;
}> */
console.log(laz2.c) // true or false
console.log(laz2.d) // error!
// --> ~
// Property 'd' does not exist on type 'LazyLet<{ a: string; b: number; } & { c: boolean; }>'.
const laz3 = laz2({ b: () => "123", d: () => 456 })
/* const laz2: LazyLet<{
a: string;
c: boolean;
b: string;
d: number;
}> */
console.log(laz3.b) // "123"
console.log(laz3.d) // 456