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

Generic symbols without an actual generic type now 'infer' {} instead of any #10990

Closed
dbaeumer opened this issue Sep 19, 2016 · 6 comments
Closed
Labels
Bug A bug in TypeScript VS Code Tracked There is a VS Code equivalent to this issue
Milestone

Comments

@dbaeumer
Copy link
Member

TypeScript Version: 2.0.2
Code

function bug<T>(obj: T): T {
    if (obj instanceof RegExp) {
        return obj;
    }
    return null;
}

function isArray<T>(arg: any): arg is Array<T> {
    return true;
}

function bug2() {
    let rules: any;

    if (isArray(rules)) {
        let str: string = rules[0];
    }
}

function bug3() {
    let values: any[];
    let strings: string[];

    if (isArray(values)) {
        strings = values;
    }
}

All this code worked in 1.8.10 but now fails in 2.0.2. From what I can read into the error message the taken type when no actual type parameter is provided is now {}. It seemed to was any before. If I change the code to for example

function bug2() {
    let rules: any;

    if (isArray<any>(rules)) {
        let str: string = rules[0];
    }
}

Everything compiles.

@mhegazy
Copy link
Contributor

mhegazy commented Sep 19, 2016

Generic type parameters with no inference sites always resulted in {} (well at least since TS 1.0).

The issue here is in TS 2.0 we started narrowing any (see #9999). before isArray(rules) did not change the type of rules since rules was declared as any; subsequently rules[0] is any. Now it does change the type to {}[] and thus rules[0] is {} and that is not assignable to string.

so the issue here is that isArray is not defined correctly. the T here is not really infer-able in any way. I understand that it can be useful for casts. consider rewriting it as:

function isArray(arg: any): arg is Array<any>;
function isArray<T>(arg: any): arg is Array<T>;
function isArray<T>(arg: any): arg is Array<T> {
    return true;
}

One thing to note, is this will cause loss of safety. I would recommend defining rules as a union type instead (assuming this is possible).

@mhegazy mhegazy added the Working as Intended The behavior described is the intended behavior; this is not a bug label Sep 19, 2016
@mhegazy
Copy link
Contributor

mhegazy commented Sep 19, 2016

I also should note that #9999 is a breaking change.

@dbaeumer
Copy link
Member Author

dbaeumer commented Sep 20, 2016

Thanks @mhegazy for the quick reply. Your explanation makes sense to me for the isArray case. But why is this failing now:

function bug<T>(obj: T): T {
    if (obj instanceof RegExp) {
        return obj;
    }
    return null;
}

I understand now that obj in the return case is narrowed to RegExp but why is this not assignable anymore to T. obj was T to begin with.

@mhegazy
Copy link
Contributor

mhegazy commented Sep 20, 2016

This is another change, in the past T was not narrowed, now it is. so RegExp is not assignable to T. I see your point of making the type of obj T & RegExp instead of just RegExp. this is the same issue discussed in #7662.

@mhegazy mhegazy added Bug A bug in TypeScript and removed Working as Intended The behavior described is the intended behavior; this is not a bug labels Sep 20, 2016
@mhegazy mhegazy added this to the TypeScript 2.1 milestone Sep 20, 2016
@mhegazy
Copy link
Contributor

mhegazy commented Sep 20, 2016

We already narrow using intersection for instanceof if the type is not a subtype of the declared type. so we should do the same for generic type arguments as well.

@mhegazy mhegazy modified the milestones: TypeScript 2.1, Future Sep 29, 2016
@mhegazy mhegazy added the VS Code Tracked There is a VS Code equivalent to this issue label Dec 16, 2016
@sandersn sandersn removed their assignment Jan 7, 2020
@Andarist
Copy link
Contributor

Andarist commented Jan 8, 2023

@RyanCavanaugh @sandersn the issue here is quite ancient. I took a look at the posted examples and I think that all of them behave OK according to today's expectations. What @mhegazy has diagnosed here as something that should be implemented:

We already narrow using intersection for instanceof if the type is not a subtype of the declared type. so we should do the same for generic type arguments as well.

also does work OK today.

I think it's reasonable to close this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript VS Code Tracked There is a VS Code equivalent to this issue
Projects
None yet
Development

No branches or pull requests

4 participants