Reputation: 6221
I have trouble understanding why TypeScript infers program.options
here as ProgramAOptions | ProgramBOptions
. Thus it cannot compile code since optA
does not exist in ProgramBOptions
. Can you explain or point me to documentation which explains this behaviour?
type ProgramName = 'a' | 'b';
type ProgramAOptions = {
optA: number;
};
type ProgramBOptions = {
optB: number;
};
type Program<T extends ProgramName> = {
name: T;
options: T extends 'a' ? ProgramAOptions : ProgramBOptions;
};name
function test(p: Program<ProgramName>) : void
{
if (p.name === 'a')
{
p.options.optA = 10; /* this line would not compile with error:
error TS2339: Property 'optA' does not exist on type 'ProgramAOptions | ProgramBOptions'.
Property 'optA' does not exist on type 'ProgramBOptions'.*/
}
}
Upvotes: 1
Views: 63
Reputation: 31815
Here is how I'd solve your problem, by explicitly declaring interfaces for every couple of names and options:
type ProgramName = 'a' | 'b';
interface ProgramAOptions {
optA: number;
};
interface ProgramBOptions {
optB: number;
};
type ProgramOptions = ProgramAOptions | ProgramBOptions;
interface Program {
name: ProgramName;
options: ProgramOptions;
}
interface ProgramA extends Program {
name: 'a';
options: ProgramAOptions;
}
interface ProgramB extends Program {
name: 'b';
options: ProgramBOptions;
}
type Programs = ProgramA | ProgramB;
function test(p: Programs): void {
if (p.name === 'a') {
p.name // is of type "a"
p.options.optA = 10; // Works
}
}
Upvotes: 2