Closed
Description
More Precise TypeFacts
for Intersections
-
TypeFact
flags - used during narrowing.- For
typeof yadda === "string"
, we have aTypeFlagsEQString
.
- For
-
Some bug was reported.
interface Meta { foo: string } interface F { (): string } function f(thing: (F & Meta) | string) { if (typeof thing === "function") { // < 4.2+: has type 'F & Meta' - expected // >=4.3+: has type 'never' - unexpected } else { // < 4.2+: has type 'string' - expected // >=4.3+: has type '(F & Meta) | string' - unexpected } }
-
With intersections, we compute type facts differently.
typefacts(A & B)
would calculate astypefacts(A) | typefacts(B)
.- In this case, it's true.
- With primitive types though, you really don't want that.
- Tagged types -
{ __yadda: void } & string
, or type variable intersections -T & string
- You really should know that you have
string
ornever
.
- Tagged types -
-
It's rare to call typefacts on a union, but intersections don't get broken down that way.
- Could be that some flags combine with an
&
(and) and some with an|
(or). - Plain ones combine with
|
, negated ones combine with&
.
- Could be that some flags combine with an
-
Conclusion: iterate on implementation
Parsing Files as Modules
- When we added the React transform, we used the existing parser infrastructure - that means the presence of a module construct (
import
/export
) is what determines whether we have a module. - Newer JSX transform implicitly imports React. Not true of the old mode.
- Also have files that always consider themselves to be ESM files, but weren't enforcing them as modules correctly.
- Have an implementation where if you're in an ESM file or in a new JSX-mode file, then we do consider those files to be modules.
- New flag -
--moduleDetection
force
,auto
,legacy
.force
is always module (except declaration files - sad)auto
- figure it out from the file extension and module usage. Mixes today's behavior, but does the right thing for.mts
etc.legacy
- everything is global unless you have a disambiguator - even.mts
/.mjs
or whatever.
- New flag -
- Does this change the behavior for a getting started experience?
- Not really -
auto
is the new default.
- Not really -
- What's the API change?
- Breaking change technically -
externalModuleIndicator
is now potentiallyboolean
.
- Breaking change technically -
- Probably should workshop the name a bit?
- Also,
auto
implies the default value. Maybe name the flag differently?
- Also,
- Also, do we need the legacy field?
- Unlikely people will use, but it's plausible.
- Should we continue emitting
export {}
in ambiguous files when using--moduleDetection force
? - JS/TS editors have a concept of an inferred project - when you have loose JS and TS files with no
tsconfig.json
/jsconfig.json
, the editors have default options they use.- Should those editors use
--moduleDetection force
? - Maybe! Should talk it over at our next editor sync.
- Should those editors use
- Action items:
- Get implementation together with LS
- Bikeshed name
- Editor sync discussion
Preserving Mapped Types Over Tuple Elements
- Can re-index into a mapped type with an intersection of its
keyof
and a type variable. - Things go a little crazy once you get a tuple type with a variadic portion in it.