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 the is operator.
A this-based type guard is assignable if the
boolean is assignable to this-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.
Promoted type guards to an actual type.
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 returns undefined.
Runtime looks for a property descriptor on the LHS, won't find one, so returns undefined.
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.
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.
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?
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 on this (!!??)
` 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 the super of the containing class.
We currently
Why is this allowed?
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 to null.
Should only be allowed in a method body of an object literal.
Should only be allowed in ES6.
Should we do inference on __proto__ for super?
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.
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 a string index signature.
Arguably more surprising of the two.
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.
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 and String types.
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.
Reactions are currently unavailable
You can’t perform that action at this time.
thistype guards (#5906)Some unaddressed concerns in PR.
Differences between parameter/this type guards
Parameter type guards check against type of parameters
thistype-guards tied to a signature`this type-guards allowed on properties
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
thison the LHS of theisoperator.A
this-based type guard is assignable if thebooleanis assignable tothis-based type guard on member.thistype predicates for properties don't allow predicates for broader types to be assigned to predicates of more specific types.boolean, so that should be allowed.getaccessors might make this too confusing.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.It would be nice if
isNumberdidn't need to be declared.Going off-topic.
Let's go back to assignability rules.
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.valuefrom superclass.Problem is we don't distinguish between getters and property descriptors.
This sort-of works in ES2015, but not actually.
fooreturnsundefined.undefined.Could write a fix to lookup if a getter exists at runtime, looks really gross.
super.propwithout using it as a call (i.e.super.prop()).In ES6, we should probably allow this.
Potential emit:
to ES2015
this.foodoesn't check the instance.What about element access syntax (i.e.
super[4 + 3])?ES6 vs ES5
What about assignment to a property on
super?(1)and(2)actually do completely different things!(1)actually sets a descriptor onthis(!!??)Resolution: 👍 (need to propose a new emit)
supershould be allowed in a computed property (when nested in a class) (#6038)superrefers to thesuperof the containing class.superin object literal causes error (#5441)__proto__is valid.__proto__is set tonull.__proto__forsuper?this.Intersection types (intersecting with
string) are not valid index signature typesTwo issues for this:
stringstring, when indexing value has astringindex signature.Is this useful?
We do hacks like this in the compiler to differentiate strings from actual paths.
But these types don't exist at runtime.
Aside: thanks to string literal types, you can do even more crazy tagging stuff.
NumberandStringtypes.Resolutions
But, this is just supporting a hack, so we should really consider giving people a better mechanism.