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 of variable is inferred from literal instead of annotation #40860

Closed
JakenVeina opened this issue Sep 30, 2020 · 3 comments
Closed

Type of variable is inferred from literal instead of annotation #40860

JakenVeina opened this issue Sep 30, 2020 · 3 comments
Labels
Duplicate An existing issue was already created

Comments

@JakenVeina
Copy link

Search Terms:
variable
literal
type inference
type annotation
TS2367
TS2339

Code

type Foo = number | "test";

let x: Foo = 5;
let y = <Foo>5;

function bar() {
    x = "test";
    y = "test";
}
bar();

if (x === "test") { // TS2367 This condition will always return 'false' since the types 'number' and 'string' have no overlap.
    console.log(x.length); // TS2339 Property 'length' does not exist on type 'number';
}
if (y === "test") {
    console.log(y.length);
}

Expected behavior:
No error should be produced here, since the variable x was declared to be of type Foo, not number, even though it was initialized with a number literal, it's not declared as a const and thus could change (and in fact does).

Actual behavior:
The compiler seems to infer the type of x as number, from the literal 5 used to initialize it, even though the variable type is explicitly declared to be of type Foo.

Playground Link:
Playground

Related Issues:
#26979
#10195

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label Oct 1, 2020
@RyanCavanaugh
Copy link
Member

Your real complaint here is that the side effect in the function wasn't considered; see #9998.

Initialization is the same as assignment, so

let x: Foo = 5;

gets the same treatment as

let x: Foo = (whatever);
x = 5;

Given this, it would be ridiculous to error on

let x: Foo = (whatever);
x = 5;
x.toFixed(); // Error, Foo might be "test" ?????

@JakenVeina
Copy link
Author

That's fair. I also think it's fair for the compiler to not recognize that side-effect. It can't investigate everything.

For context, the real-world scenario where this came up was...

interface ValidationErrorMap {
    readonly [errorCode: string]: string | ValidationErrorMap;
}

type ValidationResult = ValidationErrorMap | "success";

function combine(ReadonlyArray<ValidationResult>results): ValidationResult {
    let finalResult: ValidationResult = "success";

    for(const result of results) {
        finalResult = (result === "success") ? finalResult
            : (finalResult === "success") ? result
            : { ...finalResult, ...result };
    }

    return finalResult;
}

Here, I would definitely expect the side-effect to be recognizable, as it's happening in the same scope, just inside a loop.

@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.

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

No branches or pull requests

3 participants