Closed
Description
Always Infer Literal Types (#6554, #10676)
Basics
-
Based on complaints we've seen in the past about how literals don't "stick" for
const
// Type has type 'string' instead of '"hello"' const x = "hello";
-
Idea: the literal
1
should always start out with the type1
.- No more literal type locations.
- In a read-only location, a literal type will keep its type.
- In a mutable location, a literal type will gain its base primitive type, unless it has a contextual type.
-
Every literal type has a base primitive type.
Changes to Function Return Type Inference
- Other change is that multiple return statements always return a union of each returned type.
- For a singleton literal type, widen to the base primitive type.
- Rationale - definitely no point to inferring a singleton. Arguable whether you want the same behavior on unions.
Changes to Type Argument Inference
For a type parameter T
, a literal type argument will be inferred for T
if
T
is inferred from "top-level" occurrences (allows widening to take place later on).T
has no primitive/literal constraint (user wanted it).T
does not occur at the "top-level" in the return type (more complicated reasons).
Substitute Value of super()
For this
(#7574, #10762)
Summary:
- Not pretty.
- Not that bad.
- Perf numbers aren't much worse.
👍
@mhegazy notes:
- Issue: Return value of super() calls not used for
this
#7574 - PR: Use returned values from super calls as 'this' #10762
- ES6 semantics for inheritance indicates that the result of calling super becomes the new this
- This is why
this
cannot be used beforesuper
is called. - perf tests on the generated output seems to be on par with the previous emit, no major slowdowns
- This does not completely handle cases requiring
new.target
e.g. extendingArray
andError
- The output is not as clean as it was. but not different from capture of
this
in arrow functions - 👍
keysof
Operator (#1295, #10425)
Libraries like Ember, Backbone, and Immutable all use string literals to access properties.
Idea keysof T
: a "keys query", which returns a union of literal types for each property in T
.
Following this, you could have T[K]
which, when K
is a literal type, returns the type of a property with the name K
on T
.
function get<T, K extends keysof T>(obj: T, key: K): T[K] {
obj[key];
}
// Returns 'string'
get({name: "Daniel" }, "name");
// Error: '{ name: string }' has no property named 'nmae'.
get({name: "Daniel" }, "nmae");
- Question: Why doesn't
key
just have the typekeysof T
?- Because if
T
was something like{ name: string; age: number }
, thenkeysof T
would be"name" | "age"
.
Even if you pass in"name"
forkey
, the type system keeps the type as"name" | "age"
.
That means the return type will beT["name" | "number"]
.
In reality, you want to grab the specific literal"name"
to do a query.- We could do the "right thing", but that'd require an implicit type parameter, which would get complicated.
- Because if
Caveats: any object contxtually typed with a string
index signature will have keysof
effectively return string
on it.