Skip to content

in Operator Narrowing is Too Limited #50891

New issue

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

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

Already on GitHub? # to your account

Closed
DanielRosenwasser opened this issue Sep 21, 2022 · 3 comments
Closed

in Operator Narrowing is Too Limited #50891

DanielRosenwasser opened this issue Sep 21, 2022 · 3 comments
Assignees
Labels
Duplicate An existing issue was already created

Comments

@DanielRosenwasser
Copy link
Member

Playground Link

interface RGB {
    red: number;
    green: number;
    blue: number;
}

function setColor(value: unknown) {
    const isRGB =
        // is an object
        value && typeof value === "object" &&
        // 'red' exists and is a 'number'
        "red" in value && typeof value.red === "number" &&
        // 'green' exists and is a 'number'
        "green" in value && typeof value.green === "number" &&
        // 'blue' exists and is a 'number'
        "blue" in value && typeof value.blue === "number";

    if (isRGB) {
        const rgb: RGB = value;
    }
}

Expected: No errors
Actual Errors.

Type 'object & Record<"red", unknown> & Record<"green", unknown> & Record<"blue", unknown>' is not assignable to type 'RGB'.
  Types of property 'red' are incompatible.
    Type 'unknown' is not assignable to type 'number'.
@RyanCavanaugh RyanCavanaugh added the Needs Investigation This issue needs a team member to investigate its status. label Sep 21, 2022
@ahejlsberg
Copy link
Member

ahejlsberg commented Sep 21, 2022

This is basically a duplicate of #42384 (which in turn is a duplicate of a much older issue for the same scenario, but I can't locate that right now). You'd see the same problem if you started out with a { red: unknown, green: unknown, blue: unknown } object and applied just the typeof checks.

EDIT: The oldest related issue I can locate right now is #29827, but no doubt there are more.

@ahejlsberg
Copy link
Member

ahejlsberg commented Sep 21, 2022

It's interesting, though...

We could consider having a typeof value.red === "number" narrow the type of value by intersecting with Record<"red", number>, and we could do similar narrowing for other types of tests:

type Point = { x: number, y: number };

declare function doWithPoint(p: Point): void;

function test(p: Partial<Point>) {
    if (p.x && p.y) {
        doWithPoint(p); // Narrowed to Partial<Point> & Record<"x", number> & Record<"y", number>
    }
}

One concern would be the noise created by all the intersections, but it does seem like a workable idea.

@ahejlsberg ahejlsberg added Duplicate An existing issue was already created and removed Needs Investigation This issue needs a team member to investigate its status. labels Sep 22, 2022
@typescript-bot
Copy link
Collaborator

This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

4 participants