Description
this
type guards (#5906)
-
Some unaddressed concerns in PR.
-
Differences between parameter/this type guards
-
Parameter type guards check against type of parameters
-
this
type-guards tied to a signature -
`this type-guards allowed on properties
- Rationale for allowing on properties is we needed to allow them for get-accessors.
- Type-compatibility
-
Narrowing logic identifies when a method gets called or a property access is performed.
-
Check for a
this
-type guard, which will narrow the LHS of a property access. -
Allows an identifier or
this
on the LHS of theis
operator. -
A
this
-based type guard is assignable if the -
boolean
is assignable tothis
-based type guard on member.interface Foo { isVar: this is Bar } var foo: Foo; foo.isBar = true; // kosher
-
this
type predicates for properties don't allow predicates for broader types to be assigned to predicates of more specific types.- But that's just an assignment of a
boolean
, so that should be allowed. - Methods seem like they should still have restrictions.
get
accessors might make this too confusing.- That would mean property
- But that's just an assignment of a
-
Promoted type guards to an actual type.
-
We can now make inferences for type parameters based on type predicate types.
-
Useful for functions like
filter
.function isNumber(x: any): x is number { return typeof x === "number"; } let x = [1, 2, "a", "b"]; let y = x.filter(isNumber); // type is 'number[]'
-
It would be nice if
isNumber
didn't need to be declared.let x = [1, 2, "a", "b"]; let y = x.filter(() => typeof x === "number"); // type is 'number[]'
-
-
Going off-topic.
-
-
Let's go back to assignability rules.
- Aside: we can elaborate and give better errors as a result of this.
- Parameter (identifier) predicate types will only ever show up in the return type of a method.
-
We'll need to go back and check a little more, because certain people (like myself) signed off on it before a design meeting.
Get accessors via super
(#4465)
-
User wants to get value of accessor via
super.value
from superclass. -
Problem is we don't distinguish between getters and property descriptors.
-
This sort-of works in ES2015, but not actually.
class { value: number; constructor() { this.value = 10; } } class Derived extends Base { foo() { return super.value; } }
foo
returnsundefined
.- Runtime looks for a property descriptor on the LHS, won't find one, so returns
undefined
.
- Runtime looks for a property descriptor on the LHS, won't find one, so returns
-
Could write a fix to lookup if a getter exists at runtime, looks really gross.
- But how frequently do people write
super.prop
without using it as a call (i.e.super.prop()
). - It's not common, so it wouldn't be the norm.
- But how frequently do people write
-
In ES6, we should probably allow this.
-
Potential emit:
class A { foo; bar() { } } class B extends A { zzz() { let y = super.foo; } }
to ES2015
class A { foo; bar() { } } class B extends A { zzz() { var y = (_a = Object.getOwnPropertyDescriptor(_super.prototype, 'foo'), a && (a.get ? _a.get.call(this) : _a.value); var _a; } }
- "This isn't horrible. I mean it's awful, but not horrible."
- But this doesn't account for if this is a instance field or a prototype field.
- How deep down the rabbit hole do we want to go?
- "Elbow deep"
- "Only a couple of inches"
- If we're not making that distinction, why not just make this throw an exception.
- It's 10-characters fewer to make it throw, so why bother to change the behavior to throw?
- But nobody is getting what they expect anyway.
- Actually, it doesn't matter;
this.foo
doesn't check the instance.
- How deep down the rabbit hole do we want to go?
-
What about element access syntax (i.e.
super[4 + 3]
)?- Wait we found a bug while playing in the playground.
-
ES6 vs ES5
- Should this be legal in ES6 so long as the property exists?
- Yes.
- Should this be legal in ES6 so long as the property exists?
-
What about assignment to a property on
super
?class B extends A { zzz() { super.foo = 1; // (1) this.foo = 1; // (2) } }
(1)
and(2)
actually do completely different things!(1)
actually sets a descriptor onthis
(!!??)- ` But not
-
Resolution: 👍 (need to propose a new emit)
super
should be allowed in a computed property (when nested in a class) (#6038)
- When in a computed property,
super
refers to thesuper
of the containing class. - We currently
- Why is this allowed?
- Everyone points and yells at @bterlson.
- Resolution: 👍 (fix the bug)
super
in object literal causes error (#5441)
- This should work given that
__proto__
is valid. - Should be allowed, since it's only invalid if
__proto__
is set tonull
.- Should only be allowed in a method body of an object literal.
- Should only be allowed in ES6.
- Should we do inference on
__proto__
forsuper
?- Weird, we don't do any inference for
this
. - We shouldn't do it for one and not the other.
- Revisit that down the road.
- Weird, we don't do any inference for
- Resolution: 👍 (allow in ES6)
Intersection types (intersecting with string
) are not valid index signature types
-
Two issues for this:
- Can't define a string indexer type taking an intersection with
string
- Can't index with type intersecting with
string
, when indexing value has astring
index signature.- Arguably more surprising of the two.
- Can't define a string indexer type taking an intersection with
-
Is this useful?
- Yes, totally, we use it in the compiler to differentiate plain strings from canonical paths.
-
We do hacks like this in the compiler to differentiate strings from actual paths.
- Tags a value.
- Kind of like units of measure.
- Verification tagging in some instances.
- Data sanitization.
-
But these types don't exist at runtime.
- But that's fine, this has no runtime overhead instead of wrapping it in a tagging object.
-
Aside: thanks to string literal types, you can do even more crazy tagging stuff.
type Meters = number & "Meters"; type Feet = number & "Feet"
- But... that's bad because now you have methods of global
Number
andString
types.- Don't do that.
- But... that's bad because now you have methods of global
-
Resolutions
- Unsure of accepting other types in index signature parameters.
- For accepting intersections with string when performing an element access, 👍 (someone write a proposal for this)
-
But, this is just supporting a hack, so we should really consider giving people a better mechanism.