Skip to content

Type narrowing does not extend to return type #61537

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
shark-admin opened this issue Apr 5, 2025 · 1 comment
Closed

Type narrowing does not extend to return type #61537

shark-admin opened this issue Apr 5, 2025 · 1 comment

Comments

@shark-admin
Copy link

shark-admin commented Apr 5, 2025

🔎 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

https://www.typescriptlang.org/play/?ts=5.9.0-dev.20250405#code/C4TwDgpgBAcgrgWwgJwJYGMDSqB2ATKAXigCJdgSoAfUgMwBsB7AQwurtQA8I8SBuAFChIUbPgAqjcQGdx4CAB5MUCJ2AR802IhQYxeAHxFRKtRrxaAFGRxsaJBiwoBKKAH4oORACMUUAFxQ0sBoOADmgkLyUACinGDIENLSqIw4CgBKRsRxCUkpaQCC3tIAqjip6VmRqmCMyMBQwtC5icmVxWUVaZnZUADeAlBQANrKuNpIaFi4eAC6ga35leXMyCCZADSkzCUk25gGggC+I-BTerNzNfH1jc2x8W0FOKvrWyaq6ppBIbhh2wAYqZvhZJroZvg+oNhgBrWaBTCCYZgAAWzFsjAQgQyI2uQygbTg9GA+kCgORUEYkGQGLwiyeyx6WSgADIBoSksTSQioMDjicBAJancoLQ4Dh0MBKioAG7MehwVgQACMvUstWQDLy7WZBm2yEYjGAOOciNmkhkckgCmajFopgSADoiST9EYYVBUA6NU8nfD8ERiCRdtJKKz2ZqXVy3bMg6RyCRXJ7hvQII1OOaJFJZPJbfJ7Y7kE7qSg6dHpNz3ZThgB6WtQTherR4CDoehrHhQdD1RJS+ggKDMLReBC+ZBC4bDHs4YJUml04wQeWK5Uq33O0u0-AGo3AZw1qD1+dlwOoFttjuJAi4HvIPvAAdDqzBUJhdij8fOSdT48ASUac8vUlXs20fQccDbdB8jWQdgEYKA4GkaBmCaaJh2QhoZXgqAwAwppUWgV1GkLZcFSVdR1y3OlXBwgBZVhUSdUN-AJYZEmAOBkBwKAGOAJjQ0sajA2HTwfBQA82KPBtxEIzlOO4qAVzgaBCweT8-EIxJm27UD+0HZh0GgsB1DwAljgJfjDQAd08CBbJie96msGBjS9BAwDTJBbB4JNBWFW4GjFCUpRlMjV3UAAmD4YhBcwtCWXUqgMAwNy1WJd2NU0szwS1cxtGIRhIYj9BIOYPQJb0oDS-040IYNQ3DSM-RKurg0TZMpLTDMcry61FDtB0o1aqFD2PJsgNbdtOwIO8HyfUSNInKSZznYSCGIcKKIgSKavWzL9zGht1p0qary7OawIWkdxOQTxGGsn86xkuSOK4njlNUh11NunTbz08DOQAKzArtrNQfjGDge50OSFBpTSVip3k97eMY5iSiEhd8FcUT9D6vNCuKmMeXwMqjnMyzURsuyHKc5AXLc1APK8jRTL8gQLKAA

💻 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

Additional information about the issue

@shark-admin
Copy link
Author

I just realized this is not yet possible in TS and is a duplicate of #33014

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant