I have this type (simplified):
type T1 = {
kind: 'a';
prop: string;
} | {
kind: 'b';
prop2: number;
};
Now I want to add a property prop3: boolean
but only to the case of kind: 'a'
, like I written:
type T2 = {
kind: 'a';
prop: string;
prop3: boolean;
} | {
kind: 'b';
prop2: number;
};
I tried the following:
type T2 = T1 & { prop3: boolean }; // Not works, adds to both `kind: 'a'` and `kind: 'b'`
type T3 = T1 & { kind: 'a'; prop3: boolean } // Adds to `kind: 'a'` properly, but intersects `kind: 'b' & 'a'` for `kind: 'b'`, and thus `kind: never`, and thus the whole case is `never`, so it omits `kind: 'b'` entirely - equals to `{ kind: 'a', prop: string, prop2: string }`
I suspect the answer has something to do with the built-in utility types like Exclude
and Omit
, but can't find a proper solution.
Any help is appreciated. Thanks in advance.
I think if you're going to do this sort of thing often and need a utility type for it, you can create your own:
type IntersectExtract<T, U, V> = T extends U ? T & V : T
This means: intersect V
with just those members of the union T
that are assignable to U
:
type T2 = IntersectExtract<T1, { kind: 'a' }, { prop3: boolean; }>
/* type T2 = {
kind: 'b';
prop2: number;
} | ({
kind: 'a';
prop: string;
} & {
prop3: boolean;
}) */
declare const t2: T2;
if (t2.kind === "a") {
t2.prop3 === true // okay
} else {
t2.prop3 === true // error
// ~~~~~ <-- prop3 does not exist on type {kind: "b", prop2: number}
}
Looks like what you want.