When trying to type check the dependency between keys and values in an object, I try to define MyObject
as:
type Key = AKey| BKey
type AKey = `A${string}`
type BKey = `B${string}`
type Item<Key> =
Key extends AKey ? {a:string} :
Key extends BKey ? {b:number} :
{}
type MyObject = {[key:Key]:Item<Key>}
There is no error, however invalid inputs are accepted without errors:
let test1:MyObject = {"Afoo":{a:"yes"}}
let test2:MyObject = {"Afoo":{b:1}} // should fail
let test3:MyObject = {"Bbar":{a:"no"}} // should fail
let test4:MyObject = {"Bbar":{b:2}}
It looks like extends
is not working with string literal types or is it something else?
I know about as const
for a closed set of keys but this doesn't apply here as I need the keys set to be infinite.
CodePudding user response:
As it written now MyObject
results in:
{
[key: `A${string}`]: { a: string } | { b: number };
[key: `B${string}`]: { a: string } | { b: number };
}
That's because union AKey| BKey
is passed to Item<Key>
. But we want to resolve the value for each key separately. This can be achieved using mapped type:
type MyObject = { [K in Key]: Item<K> }
let test1: MyObject = { "Afoo": { a: "yes" } }
let test2: MyObject = { "Afoo": { b: 1 } } // now fails
let test3: MyObject = { "Bbar": { a: "no" } } // now fails
let test4: MyObject = { "Bbar": { b: 2 } }
Now MyObject
is resolved to:
{
[key: `A${string}`]: { a: string };
[key: `B${string}`]: { b: string };
}