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

Control flow based type analysis #8010

Merged
merged 70 commits into from
Apr 22, 2016
Merged

Control flow based type analysis #8010

merged 70 commits into from
Apr 22, 2016

Conversation

ahejlsberg
Copy link
Member

This PR introduces control flow based type analysis for local variables and parameters as initially suggested in #2388 and prototyped in #6959. Previously, the type analysis performed for type guards was limited to if statements and ?: conditional expressions and didn't include effects of assignments and control flow constructs such as return and break statements. With this PR, the type checker analyses all possible flows of control in statements and expressions to produce the most specific type possible (the narrowed type) at any given location for a local variable or parameter that is declared to have a union type.

Some examples:

function foo(x: string | number | boolean) {
    if (typeof x === "string") {
        x; // type of x is string here
        x = 1;
        x; // type of x is number here
    }
    x; // type of x is number | boolean here
}

function bar(x: string | number) {
    if (typeof x === "number") {
        return;
    }
    x; // type of x is string here
}

Control flow based type analysis is particuarly relevant in --strictNullChecks mode because nullable types are represented using union types:

function test(x: string | null) {
    if (x === null) {
        return;
    }
    x; // type of x is string in remainder of function
}

Furthermore, in --strictNullChecks mode, control flow based type analysis includes definite assignment analysis for local variables of types that don't permit the value undefined.

function mumble(check: boolean) {
    let x: number; // Type doesn't permit undefined
    x; // Error, x is undefined
    if (check) {
        x = 1;
        x; // Ok
    }
    x; // Error, x is possibly undefined
    x = 2;
    x; // Ok
}

The narrowed type of a local variable or parameter at a given source code location is computed by starting with the initial type of the variable and then following each possible code path that leads to the given location, narrowing the type of the variable as appropriate based on type guards and assignments.

  • The initial type of local variable is undefined.
  • The initial type of a parameter is the declared type of the parameter.
  • The initial type of an outer local variable or a global variable is the declared type of that variable.
  • A type guard narrows the type of a variable in the code path that follows the type guard.
  • An assignment (including an initializer in a declaration) of a value of type S to a variable of type T changes the type of that variable to T narrowed by S in the code path that follows the assignment.
  • When multiple code paths lead to a particular location, the narrowed type of a given variable at that location is the union type of the narrowed types of the variable in those code paths.

The type T narrowed by S is computed as follows:

  • If T is not a union type, the result is T.
  • If T is a union type, the result is the union of each constituent type in T to which S is assignable.

Thanks to @ivogabe for providing inspiration and tests for this PR.

Fixes #2388.

@ahejlsberg ahejlsberg merged commit 5ed6f30 into master Apr 22, 2016
basarat added a commit to alm-tools/alm that referenced this pull request Apr 22, 2016
@mhegazy mhegazy mentioned this pull request Apr 22, 2016
5 tasks
dokidokivisual added a commit to karen-irc/karen that referenced this pull request May 4, 2016
chore(TypeScript): Enable 'strictNullChecks' option

This tries to enable [`--strictNullChecks` option](microsoft/TypeScript#7140) of TypeScript compiler.

- [Non-nullable types by ahejlsberg · Pull Request #7140 · Microsoft/TypeScript](microsoft/TypeScript#7140)
  - [Non-strict type checking · Issue #7489 · Microsoft/TypeScript](microsoft/TypeScript#7489)
  - [[Request for feedback] Nullable types, `null` and `undefined` · Issue #7426 · Microsoft/TypeScript](microsoft/TypeScript#7426)
- [Control flow based type analysis by ahejlsberg · Pull Request #8010 · Microsoft/TypeScript](microsoft/TypeScript#8010)

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="35" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/karen-irc/karen/604)
<!-- Reviewable:end -->
@kristian-puccio
Copy link

Just trying out typescript now and working out for to get type check actions in redux. Looks like this feature could be very helpful for this?

reduxjs/redux#992

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.