Description
Abstract Constructor Types
- [[Reiteration of rules of abstract constructor, see the PR]]
- Plan to support
abstract
constructor types to theInstanceType
helper type in a follow-up release. - Who wants this?
- API Extractor is one example
- What are they doing without it?
- Hacks like
Function & { prototype: T }
.
- Hacks like
- How does the "...any" signature work? Does it preserve
abstract
? - When it comes to
abstract class
, there are some intractable problems.- Classes become nominal as soon as you add
private
/protected
. - That conflicts with our strategy of displaying things structurally.
- Unique symbol has similar issues.
- Classes become nominal as soon as you add
- Note: the quick info display is very misleading.
- Whole experience around mixin factories feels a little half-baked, but
abstract
.- Arguable point of view.
typeof class { ... }
would ideally work better.- What about
abstract
on instance sides? Seems odd that you need to declare a class to get anabstract
instance side.- We've never been 100% with classes to instances.
Preserved Origin Types for Unions and Intersections
-
Very common issue where people have an alias like
type T = "a" | "b" | "c"; // displays as `"a" | "b" | "c" | "d"` let x: T | "d";
-
Oops!
-
This is because we flatten union types out to "normalize" them.
-
This means that that there's no
"a" | "b" | "c"
union whose type can be tied back toT
. -
This PR ensures that we track the "origin" node before the types get normalized/flattened so that we can display these correctly.
-
Also other work: when we end up normalizing intersections of union types, we'll preserve the original structure of the written type for display.
-
All this means that we can do a little extra work to display things better, more consistently, avoid unrelated aliasing.
-
This manifests itself in the language service; hover over an alias before a direct usage of a union, and vice versa, and you'll get consistent results.
type T = "a" | "b" | "c"; // won't display as 'T', regardless of whether // you hover over T first. let x: "a" | "b" | "c";
-
-
So we'll do better at displaying the type that you wrote!
-
We also do this for
keyof
types now as well; we'll preservekeyof
s.- Super useful for code which maps over every possible property, where you really DON'T want to have a union of 1000 literals.
-
Is there a cost to this?
- Yes, we do we a bit of work being done.
-
This is a little bit unfortunate because you can't really expand these out.
-
We do something with literal types and fresh types - is there a similar approach we could use here?
-
As of 3 days ago, we started caching relations between unions, and we have other heuristics - so that's part of why the perf isn't too bad.
-
Does it make sense to have a first-class alias type internally?
- Would generalize the aliasing logic farther than unions and
keyof
.
- Would generalize the aliasing logic farther than unions and
-
Can imagine some editor UI to give the alternative representation to avoid opaque type display.
-
Conclusion: looks good - let's get it in.