Skip to content

Type narrowing does not extend to return type #61537

Duplicate of#33014
@shark-admin

Description

@shark-admin

🔎 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

Activity

shark-admin

shark-admin commented on Apr 5, 2025

@shark-admin
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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @shark-admin

        Issue actions

          Type narrowing does not extend to return type · Issue #61537 · microsoft/TypeScript