镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

Apply type inference to mapObject[s.kind] #20190

Description

@mhchem

TypeScript Version: 2.6.1

Description

I am very impressed by the type inference TypeScript can do with switch and for...else statements.
I miss, however, type inference for map object lookups.

Code

type Named = { kind: "named", id: string };
type Decimal = { kind: "decimal", id: number };
type Hex = { kind: "hex", id: number };
type Entity = Named | Decimal | Hex;
let areaFunctions = {
    "named": function (s: Named) { return "&"+s.id+";"; },
    "decimal": function (s: Decimal) { return "&#"+s.id+";"; },
    "hex": function (s: Hex) { return "&#x"+s.id+";"; },
    "something else": {}
}
// works
let printEntity1 = function (s: Entity) {
    switch (s.kind) {
        case "named": return areaFunctions["named"](s);
            // This works perfectly, TS knows that s can only be to type 'named', here
            // It also knows the function definition and sees that both match
        case "decimal": return areaFunctions["decimal"](s);
        case "hex": return areaFunctions["hex"](s);
    }
}
// does not work
let printEntity2 = function (s: Entity) {
    return areaFunctions[s.kind](s);  // error, although it is equivalent to printEntity1
}
// does not work, although a common JS pattern
let printEntity3 = function (s: Entity) {
    if (areaFunctions[s.kind]) {
        return areaFunctions[s.kind](s);  // type inference does not work
    }
    return "-";
}

Expected behavior:
printEntity2 would compile

Actual behavior:
But it doesn't. I am forced to expand a single line into a long switch statement (just 3 lines here, but a lot more -- and often used -- in my project).

Activity

  1. aluanhaddad commented on Nov 21, 2017

    @aluanhaddad
    Contributor

    As a workaround, you can write

    let printEntity2 = function <K extends Entity['kind']>(s: Entity & {kind: K}) {
        return areaFunctions[s.kind](s); 
    };
  2. mhegazy commented on Nov 21, 2017

    @mhegazy
    Contributor

    There are multiple features that are not supported today that contribute to blocking this scenario.. first, The main is that a union property is not callable unless all variants have the same signature. so we would need #7294 first to be able to address this issue. Second we will need to distribute the union over the whole call expression, i,.e. the type of areaFunctions[s.kind](s) would be typeof areaFunctions["named"](s) | tyoeof areaFunctions["decimal"](s) | | tyoeof areaFunctions["hex"](s); then we will need to do some narrowing on s in each branch based on the type of s.kind.

    #7294 is the main issue, we currentlly have now way of resolving a union call.

  3. typescript-bot commented on Dec 6, 2017

    @typescript-bot
    Contributor

    Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.

  4. locked and limited conversation to collaborators on Jun 14, 2018
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

    Design LimitationConstraints of the existing architecture prevent this from being fixed

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions