Duplicate of#33014
Description
🔎 Search Terms
"Type narrowing", "generic dependent return type", "GADT", "GADT expression evaluation"
🕗 Version & Regression Information
This is the behavior in every version I tried, and I reviewed the FAQ for entries about "narrow", "dependent". I also looked through all the headings and didn't see any relevant sections.
⏯ Playground Link
💻 Code
type NumericKind = "int" | "float" | "fixed";
type KindToTsType<K extends NumericKind> = K extends ("int" | "float") ? number : string;
type Expression<R> = ExpressionAbsUnion<R>;
export type ExpressionAbsUnion<R> = {
[K in NumericKind]: ExpressionUnary<R, "abs", K>;
}[NumericKind];
export type ExpressionUnary<R, K extends string, F extends NumericKind> = {
kind: K;
phantom: R[];
resultKind: F;
operand: Expression<R> & { resultKind: F };
}
export function evaluate2<R, E extends Expression<R>>(expr: E, root: R): KindToTsType<E["resultKind"]> {
if (expr.kind == "abs" && expr.resultKind == "int") {
let x: KindToTsType<typeof expr.resultKind>;
// x is declared correctly as number
const operand = evaluate2(expr.operand, root);
// operand is declared correctly as number
// ----------------------------------------------
// ------------ THE ERROR IS HERE: ------------
// ----------------------------------------------
// The return value of type number is incorrectly rejected without type assertion:
return Math.abs(operand) as KindToTsType<E["resultKind"]>;
}
throw new Error("Not implemented");
}
🙁 Actual behavior
The declared return type of KindToTsType<E["resultKind"]>
and the actual return type of number
in the narrowed branch are not compatible.
🙂 Expected behavior
E
should be proven to be ExpressionUnary<R, "abs", "int">
in the branch and therefore the compiler should know that KindToTsType<E["resultKind"]>
is equal to number
Activity
shark-admin commentedon Apr 5, 2025
I just realized this is not yet possible in TS and is a duplicate of #33014