Skip to content
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

Regression in 4.8 where string union type widens to string #50635

Open
me4502 opened this issue Sep 5, 2022 · 6 comments · May be fixed by #50759
Open

Regression in 4.8 where string union type widens to string #50635

me4502 opened this issue Sep 5, 2022 · 6 comments · May be fixed by #50759
Assignees
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue Has Repro This issue has compiler-backed repros: https://aka.ms/ts-repros Rescheduled This issue was previously scheduled to an earlier milestone

Comments

@me4502
Copy link
Member

me4502 commented Sep 5, 2022

Bug Report

🔎 Search Terms

string union widening, string union regression, union widening

🕗 Version & Regression Information

This regression occurred in 4.8.0, and can be reproduced with the 4.8.0-beta, and nightly (4.9.0-dev.20220904) tag in TS Playground. This works with 4.7.4.

  • This changed between versions 4.7.4 and 4.8.0-beta

I feel like this might be related to the Improved inference from binding patterns change

⏯ Playground Link

Playground link with relevant code

To reproduce, hover over the "isWorking" variable to see that the type definition includes a union of the strings. Switch to 4.8.0-beta, and note that the type definition is now just string.

💻 Code

interface Guard<T> {
    (val: unknown): val is T;
}

type ObjectGuard<T> = {
    [key in keyof T]: Guard<T[key]>;
};

function isObject(val: unknown): val is Record<string, unknown> {
    return val !== undefined && val !== null && typeof val === 'object' && !Array.isArray(val);
}

function isObjectOfShape<T>(
    value: unknown,
    shape: ObjectGuard<T>,
): value is T {
    if (!isObject(value)) {
        return false;
    }
    let validShape = true;

    for (const key in shape) {
        const guard = shape[key];
        if (guard && !guard(value[key])) {
            return false;
        }
    }

    return validShape;
}

function createObjectGuard<T>(guard: ObjectGuard<T>) {
    return (val: unknown): val is T => isObjectOfShape(val, guard);
}

function asLiteral<T extends (string | boolean | number)[]>(...literals: T) {
    return (val: unknown): val is T[number] => {
        return literals.includes(val as T[number]);
    };
}

// See type of `isWorking` - should include the type key as a union of strings
const isWorking = createObjectGuard({
//    ^?
    type: asLiteral('these', 'should', 'be', 'a', 'union'),
});

🙁 Actual behavior

String union type is widened to string.

🙂 Expected behavior

String union type remains a union, rather than widening

@andrewbranch andrewbranch added the Has Repro This issue has compiler-backed repros: https://aka.ms/ts-repros label Sep 7, 2022
@typescript-bot
Copy link
Collaborator

typescript-bot commented Sep 8, 2022

👋 Hi, I'm the Repro bot. I can help narrow down and track compiler bugs across releases! This comment reflects the current state of the repro in the issue body running against the nightly TypeScript.


Issue body code block by @me4502

⚠️ Assertions:

  • const isWorking: (val: unknown) => val is { type: string; }

Historical Information
Version Reproduction Outputs
4.8.2

⚠️ Assertions:

  • const isWorking: (val: unknown) => val is { type: string; }

4.4.2, 4.5.2, 4.6.2, 4.7.2

⚠️ Assertions:

  • const isWorking: (val: unknown) => val is { type: "these" | "should" | "be" | "a" | "union"; }

@lll000111

This comment was marked as off-topic.

@typescript-bot
Copy link
Collaborator

The change between 4.7.2 and 4.8.2 occurred at a2b785b.

@andrewbranch
Copy link
Member

@typescript-bot agrees with your guess about the cause, which is strange and definitely unintentional since there is no binding pattern in the repro 🤔

@HolgerJeromin
Copy link
Contributor

I think the milestone should be adjusted because that ship has sailed... :)

@andrewbranch
Copy link
Member

Thanks. I forgot to update this issue, but we decided that the fix looked a little risky to ship in a patch when weighed against the small number of reports of this issue we’ve gotten.

@RyanCavanaugh RyanCavanaugh added the Rescheduled This issue was previously scheduled to an earlier milestone label Feb 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue Has Repro This issue has compiler-backed repros: https://aka.ms/ts-repros Rescheduled This issue was previously scheduled to an earlier milestone
Projects
None yet
6 participants