What does the "strict this" world look like?
We will check this just as if it was an argument today.
Consider
classFoo{m(){this.blah();// ...}blah(){// ...}}letfoo: Foo;lete: ()=>void=foo.m;e();- That example will crash because
m has been orphaned from its Foo instance.
Strict this-checking aims to fix this issue.
this appears in the parameter list for functions and function types.
this types affect assignability of signatures:
typeEventA=(this: Element,x: string)=>void;typeEventB=(this: void,x: string)=>void;leta: EventA;letb: EventB;a=b;// Error: 'void' isn't enough for a method needing an 'Element' for 'this'.b=a;// Okay: No problem with getting *more* than you expect.
- Assignability is still bivariant for a
this parameter
In strict-this mode, the following's an error:
functionfoo(s: string){this.abc;// Error: 'this' is implicitly a 'void'.}Arrow functions will always hold the value of this from their containing scope.
Free-standing functions implicitly get a void type for this.
Methods in classes implicitly have a this type of this.
- Hopefully this is not very surprising.
- This prevents incorrectly "ripping off the method" (
this orphaning) from the first example.
Static methods have a this type of typeof Foo where Foo is the containing class.
Does this fix the bind function?
Why do we need a flag?
It breaks existing code for when your methods have no dependency on this.
Occurs several types in the compiler.
Problems sprout up between methods signatures and function type literals:
interfaceFoo{a(): void;b(): void;}interfaceBar{a: ()=>void;b: ()=>void;}Foo methods implicitly get a this: this type, while Bar methods get a this: void type!- We need to be prescriptive and explain to people how to write definitions.
- People are still going to run into such gotchas.
By default, without the strict-this flag, there will be no implied this type.
But we still want contextual typing to work correctly:
addOnClick(function(e){// 'this' has the 'Element' type.this./*|*/// |// +-- Members of the 'Element' type.});What about object literals?
If the object is contextually typed by X, methods will get the this type of X.
varo: X={x: 10,m(){this// has type 'X'}}An object literal with no contextual type just grabs the type of the object literal:
varo: X={x: 10,m(){this// has type '{ x: number; m(this: /*typeof o?*/); }}'}}- Uh-oh, how will the declaration emitter and language-service print the type of
o?
Speaking of surfacing the representation of these types...
interfaceFoo{bar();}// What is the type of 'foo'? (this: this) => void?constfoo=foo.bar;So are all these very big changes going to need these sorts of flags?
- Are we going to have a "very strict mode"?
Do overload this parameters need to match?
Joke of the day
Breaking Changes
"use strict" changes for modules (#3676)
emitNonStrictModules."use strict"for classes?Defaulting to built-in promises
async/await.asynccode.Features (and potential breaking changes)
Specifying
thistypes for functions (#6739)What does the "strict
this" world look like?We will check
thisjust as if it was an argument today.Consider
mhas been orphaned from itsFooinstance.Strict
this-checking aims to fix this issue.thisappears in the parameter list for functions and function types.thistypes affect assignability of signatures:thisparameterIn strict-
thismode, the following's an error:Arrow functions will always hold the value of
thisfrom their containing scope.Free-standing functions implicitly get a
voidtype forthis.Methods in classes implicitly have a
thistype ofthis.thisorphaning) from the first example.Static methods have a
thistype oftypeof FoowhereFoois the containing class.Does this fix the
bindfunction?Why do we need a flag?
It breaks existing code for when your methods have no dependency on
this.Occurs several types in the compiler.
Problems sprout up between methods signatures and function type literals:
Foomethods implicitly get athis: thistype, whileBarmethods get athis: voidtype!By default, without the strict-
thisflag, there will be no impliedthistype.But we still want contextual typing to work correctly:
What about object literals?
If the object is contextually typed by
X, methods will get thethistype ofX.An object literal with no contextual type just grabs the type of the object literal:
o?Speaking of surfacing the representation of these types...
So are all these very big changes going to need these sorts of flags?
Do overload
thisparameters need to match?Unique types/tagged types/opaque types
People keep asking for this.
Ideas from last time:
The biggest question last time was what the behavior was for the type alias example (i.e.
Path).We're thinking that
Pathwill be printed asPath.This approach, combined with intersections, allows you to "compose" on existing types.
You can write
Path & Lowercased.Unique interfaces are useful for preventing people from forging nodes.
What about if a base is unique?
Does
uniqueaffect the static side?