Is there a way to write this function such that there is no type casting?
function insert<O extends object, K extends keyof O>(parent: O, key: K) {
type Item = O[K] extends Array<infer E> ? E : never;
return (entry: Item) => (key in parent)
? (parent[key] as Item[]).push(entry)
: (parent[key] as Item[]) = [entry];
}
I would like to add a constraint, so that O[K]
is assumed to be an array inside of the function's body. Object-key combinations which don't satisfy this constraint should not typecheck.
Edit
Based on the answers and my own experimentation I managed to bring it closer to having no casts:
function insert<I, K extends keyof O, O extends { [key in K]?: I[]; }>(parent: O, key: K, item: I) {
(key in parent)
? parent[key].push(item)
: parent[key] = [item] as O[K];
}
However, I still have to use a single cast as O[K]
, otherwise I get the following error:
'I[]' is assignable to the constraint of type 'O[K]', but 'O[K]' could be instantiated with a different subtype of constraint 'I[]'. ts(2322)
Edit 2:
I've prepared a TypeScript Playground with some example test cases, to make my question less confusing: playground
You can achieve what you trying to do via Maps in typescript. You can easily convert the maps to JSON objects whenever needed