Reputation: 7025
Can I constrain the value type of a map entry depending on the item's key?
type Thing<T extends string = any> = {
type: T
}
type ThingMap<T extends Thing> = {
[K in T["type"]]: T
}
interface A {
type: "A",
foo: boolean,
}
interface B {
type: "B",
}
// This compiles.
const map: ThingMap<A | B> = {
A: { type: "A", foo: true },
B: { type: "B" },
}
// But this also compiles, when it should not.
const map: ThingMap<A | B> = {
A: { type: "A", foo: true },
B: { type: "A", foo: true },
}
Upvotes: 4
Views: 1222
Reputation: 249466
You want to ensure that for a specific K
the type of the key is not the whole union (ie T
) but rather just the member of the union with the type K
. You can use Extract
to get the member of the union that has the property type
of type K
:
type Thing<T extends string = any> = {
type: T
}
type ThingMap<T extends Thing> = {
[K in T["type"]]: Extract<T, { type : K }> // Extract the union member that has { type: K }
}
interface A {
type: "A",
foo: boolean,
}
interface B {
type: "B",
}
// This compiles.
const map: ThingMap<A | B> = {
A: { type: "A", foo: true },
B: { type: "B" },
}
// Err now
const map2: ThingMap<A | B> = {
A: { type: "A", foo: true },
B: { type: "A", foo: true },
}
Upvotes: 5