I'm struggling with this error message in TypeScript. I've looked at the following SO answers and I simply don't understand the solutions.
Here is a stripped down version of my code with the error:
interface R {
field: string;
operator: string;
value: any;
}
interface RG {
combinator: 'and'|'or';
rules: (R|RG)[];
}
interface RGIC {
rules: (RGIC|R|string)[];
}
type RGT = RG | RGIC;
const f = <T extends RGT>(r: T): T => {
if ('combinator' in r) {
return { combinator: 'and', rules: [] }; // <-- TS error here
}
return { rules: [] }; // <-- TS error here
}
What I want to express is that if r is of type RG, then function f will return an object that is also type RG. If r is of type RGIC, then function f will return an object that is also type RGIC. But this error is confounding me.
CodePudding user response:
The problem you're running into is that generic constraints of the form T extends RGT does not mean "T must be exactly either RG or RGIC". All it implies is that T is compatible with RGT, meaning that it is a subtype of or assignable to RGT. There are subtypes of RGT which are more specific than either RG or RGIC, such as:
interface Whaa {
combinator: 'or',
rules: R[],
brainCellCount: number;
}
const whaa: Whaa = {
combinator: 'or',
rules: [],
brainCellCount: 86e9
}
The Whaa interface is assignable to RG; every Whaa is a valid RG. But a Whaa has a combinator which must be "or", and it also has an additional brainCellCount property of type number.
If your function f has a call signature like this:
declare const f: <T extends RGT>(r: T) => T;
you're saying that the return type of f will be exactly the same as the type of the passed-in r. And therefore the following call will produce a result of type Whaa also:
const hmm = f(whaa);
// const hmm: Whaa
And if so, then this will be fine:
hmm.brainCellCount.toFixed(2); // no compiler error
// BUT AT RUNTIME: 