Initially, it is important to mention that TypeScript has the ability to deduce the correct type of Bar
when checking the name
property within an if
statement:
if (bar.name === "A") {
bar.aData; // No error, as 'ABar' type is assigned to 'bar' here.
}
This approach may suffice based on your code structure. However, if you still wish to utilize the getBar
function, there are alternative methods you can explore:
The first option involves using a different type that links each specific Bar
type with its corresponding name. For example:
type BarMap = {
A: ABar;
B: BBar;
}
By employing a generic function, looking up the correct associated type based on the name becomes straightforward:
function getBar<T extends BarName>(foo: Foo, name: T): BarMap[T] {
// @ts-ignore: Despite TypeScript's complaint, this solution works effectively.
return foo.bar.name === name ? foo.bar : null;
}
Although an error message may appear on the return line, overlooking it should not be problematic since functionality remains intact at runtime with accurate inference:
let aBar = getBar(foo, 'A'); // Type: ABar | null
let bBar = getBar(foo, 'B'); // Type: BBar | null
If an invalid name from the BarName
list is provided, an error will be triggered:
let cBar = getBar(foo, 'C') // Error: Argument of type '"C"' is not assignable to parameter of type '"A" | "B"'
Alternatively, the second option consists of incorporating overload signatures in the function, enabling explicit definition of the return type for each combination of parameters:
function getBar(foo: Foo, name: 'A'): ABar | null;
function getBar(foo: Foo, name: 'B'): BBar | null;
function getBar(foo: Foo, name: BarName): Bar | null {
return foo.bar.name === name ? foo.bar : null;
}
This method achieves the same inference and generates an error upon receiving an unauthorized name
. Additional overload signatures could also be included to specify a bare null
return type for unknown keys.
Selecting between these solutions largely depends on the maintainability aspect tailored to your specific use case.
Playground Link