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

Type narrowing doesn't work for class using generic Readonly<Props> #22137

Closed
ms-markda opened this issue Feb 23, 2018 · 4 comments
Closed

Type narrowing doesn't work for class using generic Readonly<Props> #22137

ms-markda opened this issue Feb 23, 2018 · 4 comments
Labels
Investigating Is in active investigation Suggestion An idea for TypeScript
Milestone

Comments

@ms-markda
Copy link

TypeScript Version: "2.8.0-dev.20180221"
Not in "2.7.0-rc"

Search Terms: type narrowing class generics function method call props readonly

Code

// Loose function or method. Same result.
declare function bar(thing: string): void;

interface Base {
    thing?: string;
}
class Example<Props extends Base> {
    props: Readonly<Props>;
    mutableProps: Props;
    base: Readonly<Base>;

    foo() {
        if (this.props.thing) {
            this.props.thing.toString(); // No error
            bar(this.props.thing); // Error!
        }
        if (this.mutableProps.thing) {
            bar(this.mutableProps.thing); // No error
        }
        if (this.base.thing) {
            bar(this.base.thing); // No error
        }
    }
}

Expected behavior:

No error.

Actual behavior:

TypeScript error, but only with that combination of generics, Readonly, a class, and calling a function. Remove any one of those factors and it works as expected. Some examples of that are also shown above.

Argument of type 'P["thing"]' is not assignable to parameter of type 'string'.
  Type 'string | undefined' is not assignable to type 'string'.
    Type 'undefined' is not assignable to type 'string'.

Playground Link:

Note: Turn on StrictNullChecks.

https://www.typescriptlang.org/play/#src=%0D%0A%2F%2F%20Loose%20function%20or%20method.%20Same%20result.%0D%0Adeclare%20function%20bar(thing%3A%20string)%3A%20void%3B%0D%0A%0D%0Ainterface%20Base%20%7B%0D%0A%20%20%20%20thing%3F%3A%20string%3B%0D%0A%7D%0D%0Aclass%20Example%3CProps%20extends%20Base%3E%20%7B%0D%0A%20%20%20%20props%3A%20Readonly%3CProps%3E%3B%0D%0A%20%20%20%20mutableProps%3A%20Props%3B%0D%0A%20%20%20%20base%3A%20Readonly%3CBase%3E%3B%0D%0A%0D%0A%20%20%20%20foo()%20%7B%0D%0A%20%20%20%20%20%20%20%20if%20(this.props.thing)%20%7B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20this.props.thing.toString()%3B%20%2F%2F%20No%20error%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20bar(this.props.thing)%3B%20%2F%2F%20Error!%0D%0A%20%20%20%20%20%20%20%20%7D%0D%0A%20%20%20%20%20%20%20%20if%20(this.mutableProps.thing)%20%7B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20bar(this.mutableProps.thing)%3B%20%2F%2F%20No%20error%0D%0A%20%20%20%20%20%20%20%20%7D%0D%0A%20%20%20%20%20%20%20%20if%20(this.base.thing)%20%7B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20bar(this.base.thing)%3B%20%2F%2F%20No%20error%0D%0A%20%20%20%20%20%20%20%20%7D%0D%0A%20%20%20%20%7D%0D%0A%7D%0D%0A

Related Issues:

None that I am aware of. This showed up when updating TypeScript, so it is probably a recent regression.

@ghost
Copy link

ghost commented Feb 23, 2018

Repro:

function f<T extends { x?: number }>(o: Readonly<T>) {
    if (o.x) {
        o.x.toExponential(); // Hover over 'x' shows number
        const n: number = o.x; // Error. Hover over 'x' shows `T["x"]`
    }
}

@ghost ghost added the Bug A bug in TypeScript label Feb 23, 2018
@mhegazy
Copy link
Contributor

mhegazy commented Feb 27, 2018

narrowing does not work on generic types in general, we try to fake it in some instances, e.g. property access or call expressions. #22096 should handle that.

@deregtd
Copy link

deregtd commented Apr 27, 2018

I just ran into this too. It's basically always going to happen when trying to build an abstract React component with an extensible props model, unfortunately. :(

@ahejlsberg
Copy link
Member

Fixed in 4.3 and later, no longer reproduces. Closing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Investigating Is in active investigation Suggestion An idea for TypeScript
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants