To go with union types, you should declare some common property for all unions.
For example type
or kind
.
See next example:
interface Test {
property: SpecialProperty;
}
type PropA = 'a'
type PropB = 'b'
type PropC = 'c'
//https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes-func.html#discriminated-unions
export type SpecialProperty =
| {
type: 'A',
withPropA: PropA;
}
| {
type: 'B',
withPropB: PropB;
}
| {
type: 'C'
withPropC: PropC;
}
function test(param: Test) {
if (param.property.type === 'A') {
const prop: PropA = param.property.withPropA;
}
if (param.property.type === 'B') {
const prop: PropB = param.property.withPropB;
}
}
Because this is how TypeScript discrimunated unions works
Playground
I know, I know, now you might say to me:
Wait, I can't change my SpecialProperty
, because this type is from third party library, I don't have control over this type.
In this case you can use next utils:
type PropA = 'a'
type PropB = 'b'
type PropC = 'c'
export type SpecialProperty =
| {
withPropA: PropA;
}
| {
withPropB: PropB;
}
| {
withPropC: PropC;
}
// credits goes to https://stackoverflow.com/questions/65805600/struggling-with-building-a-type-in-ts#answer-65805753
type UnionKeys<T> = T extends T ? keyof T : never;
type StrictUnionHelper<T, TAll> =
T extends any
? T & Partial<Record<Exclude<UnionKeys<TAll>, keyof T>, never>> : never;
type StrictUnion<T> = StrictUnionHelper<T, T>
type StrictUnionWrapper = StrictUnion<SpecialProperty>
interface Test {
property: StrictUnionWrapper;
}
function test(param: Test) {
if (param.property.withPropA) {
const prop: PropA = param.property.withPropA;
}
if (param.property.withPropB) {
const prop: PropB = param.property.withPropB;
}
}
Playground
Personally, I use next typeguard for such kind of check:
const hasProperty = <T, U extends string>(obj: T, prop: U): obj is T & Record<U, unknown> =>
Object.prototype.hasOwnProperty.call(obj, prop);
const foo = (arg: unknown) => {
if (hasProperty(arg, 'age')) {
const b = arg // Record<"age", unknown>
b.age // ok
}
}
Playground