Closed
Description
CommonJS interop
-
Let's call this
esModuleInterop
. -
This PR gives people the Babel behavior that synthesizes a namespace with a default export with plucked properties.
- We want people to actually use this because it gives people a migration path to using Node's interop scheme for ES modules.
-
One change:
allowSyntheticDefaultExports
no longer actually allows you to default-import from.ts
and.js
files where inappropriate. Only from.d.ts
files. -
What about calling and constructing namespace imports?
import * as express from "express" express();
- When using this flag, this will break; otherwise, users will get the same behavior.
-
Do we want to introduce an error?
- That's considered breaking for most people.
-
But we want to push people to use best practices.
- Put it as a default in
tsc --init
.
- Put it as a default in
-
Also, if a
.d.ts
file has a variable named__esModule
, then we do the "right" thing.- Should we start emitting
__esModule
in.d.ts
files?- Seems arguable based on the output and the intent.
- We can revisit this.
- Seems arguable based on the output and the intent.
- Should we start emitting
Comparability Relationship Adjustment
- The comparability relationship is somewhat limited in what it can express.
- Original differences between comparability are with union source types and optionality.
const x1 = { a: 1 as 1, b: "abc" };
const x2 = { a: 1, b: "abc" as "abc" };
if (x1 === x2) {
// ~~~~~~~~~
// Error
}
interface T1 { x: number }
interface T2 { y: number }
let x = { x: 100, y: 200 } as T1
let y = { x: 100, y: 200 } as T2
if (x === y) {
// ~~~~~~~
// Error
}
function f<T extends { a: number }, U>(x: T, y: U, z: { a: number}) {
// All of these are allowed...
let o = {};
z === {};
x === {};
o === {};
o === y;
x === { a: 42 }
// but not this...
x === y;
// ~~~~~~~
// Error!
}
- These are incomparable - we don't go bidirectionally on the
a
property nor theb
property.- We only check both ways at the top level.
- Other issues: seems arguable whether
never
should be comparable to/from anything apart fromnever
. - Perhaps we want to change comparability to only concern itself when things are potentially true.
- Only disallow when a comparison could never occur.
- Primitives/literal types are comparable to/from their base primitive "family" type.
- When comparing two object types, only check for properties present in both.
- We speculated about this when we first did comparable; do people actually run into this a lot?
- Well it's not unsound.
- Could you compare a function to an array?
- Yes.
- If you want to do this, it seems like you want to give users a way to say "no, this type is really not the type"
- Sounds like we need two type relationships: comparable and castable.
- It also feels kind of weird that in the true branch, you can't even assign one to the other after the fact.
- Should we just stop applying checks entirely around type assertions?
- No.
- Conclusion:
- Original use case should still be fixed - base primitive types & enum types are always comparable to/from their literal type.
- Hold off on the other changes.