Description
this
-types for functions (#6739)
- Defines ability to define type of
this
for the scope of a function. - If you're in a class,
this
is assumed to have the type of the class itself.- You can still override this by giving an explicit type to
this
.
- You can still override this by giving an explicit type to
Strict this
checks
- Problem: cognitive burden by creating a distinction between types of methods and properties with function types.
- Looked at performance against
master.
- Incompatible with old code in some cases.
- Need to update
.d.ts
files. - Huge undertaking.
- Already tons of stuff for
- Need to update
- Options in light of this.
- We can take neither.
- We can take the backwards-compatible stuff, forget the strict
this
checking. - We can take both, and give people a heads up that there's going to be a perf hit for strict
this
checking.
- Conclusion: hold off on strict-
this
.
No implicit this
- Should we have that?
- Yes!
- Should it be part of
noImplicitAny
?- Well that breaks code.
- You'd need a suppressing flag.
- Nobody likes that, so
noImplicitThis
would not be umbrella'd.
Library modularization (#6974)
-
Background: hard to say what environments will have what at runtime.
Our libraries try to be all-encompassing.The workaround has been to modify
lib.d.ts
on your own, but nobody wants to do that. -
Current solution: granular libraries.
-
What about ambient decorators?
- Let's come back to that.
-
You have
es6.array.d.ts
,es6.collection.d.ts
, etc. -
New
--lib
flag, takes a list of options.- You can still just specify
es6
as the lib as an aggregate flag (includees6.*.d.ts
). - Also have an
es7.d.ts
for all one functions that were added to ES7. --target
toggles the default if--lib
isn't specified.--target es2015
still includeslib.es6.d.ts
.
- What about ES2015? ES6 technically doesn't exist.
- Everyone hates the official name.
- We have no choice. ¯_(ツ)_/¯
- You can still just specify
-
So by default, you get the ES3 lib?
- Sort of. It's more like ES5.5. We haven't split out the ES3/ES5 stuff.
- Why?
- Backwards compatibility.
- So due to back-compat, is DOM always in
lib.d.ts
?- Yes?
- But you can just use
--lib es5
and add from there on.- To add to that, you make it
--lib es5,dom
.
- To add to that, you make it
- But we could always add
--lib node
.
- Sort of. It's more like ES5.5. We haven't split out the ES3/ES5 stuff.
-
What about granular transformations?
- People want
async/await
because Node has it, but as soon as you try to do ES6 emit, you run into problems like Node not supporting destructuring. - That's the next step.
- People want
Conditional compilation stuff
- We're not fully committed to this.
Granularity
- The granularity is great.
- But there are some clear defaults.
- Are there situations where people need all this granularity?
- Can overwhelm users, can become a maintenance headache.
- Let's keep these split up, not commit to them just yet.
Control Flow Analysis For Everything (#2388)
- Background:
- We needed reachability analysis.
- Now we need control flow-based type analysis.
- Now, we've subsumed reachability analysis with our work on control flow-based type analysis.
- We now track all assignments and type-guards.
- Assignments are now considered type-guards themselves as well.
Consider
function countLines(text: string[]) {
let count: number;
for (const line of text) {
if (line.length !== 0) {
count = count + 1;
}
}
return count;
}
-
Our new checks will now yell at you for forgetting to initialize
count
and not informing us thatcount
could beundefined
. -
Even if you initialize it at the wrong point.
function countLines(text: string[]) { let count: number; for (const line of text) { count = 0; // not good enough - this loop might never execute! if (line.length !== 0) { count = count + 1; } } return count; }
-
We also infer correctly from falling through.
function countLines(text: string[]) { if (text) { let count: number = 0; for (const line of text) { if (line.length !== 0) { count = count + 1; } } return count; } }
countLines
has typenumber | undefined
since you implicitly returnedundefined
.
Assignments as a new type guard point
declare function getNumberOrString(): number | string;
var x = getNumberOrString(); // has type 'number | string'
if (typeof x === "string") {
x; // has type 'string'
x = 1000; // still okay to assign a 'number'
x; // has type 'number'
}
Shortcomings
Array accesses
Technically we should be introducing undefined
from array indexing, but this would be such a massive pain for users that we can't consider this path.
Variable capture in closures
We don't track usage of a variable's use within a function.
function uh_oh() {
return s.slice();
}
var s: string;
uh_oh(); // no error.
Potential for other work
- Could we use this logic for checking for
this
beforesuper
, etc.?- Yes!