Repository navigation
Design Meeting Notes, 12/10/2021 #47151
Description
Activity
- addedDesign NotesNotes from our design meetingsNotes from our design meetings
on Dec 14, 2021 DanielRosenwasser commented
on Dec 14, 2021 MemberAuthorMore actionsPR up for correlated union types is up #47109
Reacted by Sean VieiraHello! I'm the developer behind esbuild. I noticed that you're running the TypeScript compiler through esbuild, so I couldn't help trying it out myself. I've been meaning to do cross-module enum inlining so I did a quick implementation and tried it out on the branch in #46567. Here's a simple benchmark of the result:
lib/tsc.jsesbuild 0.14.6 esbuild 0.14.7 fixes + esbuild 0.14.6 fixes + esbuild 0.14.7 Type check time 2.96s 5.31s (1.79x) 4.94s (1.67x) 3.45s (1.17x) 2.95s (1.00x) These tests measure the time to type check the Rollup code base (with fixes for type errors due to the TypeScript upgrade). As you can see, bundling with esbuild after inlining enums results in a TypeScript compiler build that's the same speed as the one in
lib/tsc.js.But I had to fix a bug in that branch that was slowing things down a lot (the "fixes" columns in the table):
diff --git a/src/compiler/corePublic.ts b/src/compiler/corePublic.ts index 11c5416b54..4334edad7f 100644 --- a/src/compiler/corePublic.ts +++ b/src/compiler/corePublic.ts @@ -138,6 +138,7 @@ namespace NativeCollections { export function tryGetNativeMap(): MapConstructor | undefined { // Internet Explorer's Map doesn't support iteration, so don't use it. // eslint-disable-next-line no-in-operator + const Map = globalThis.Map as any; return typeof Map !== "undefined" && "entries" in Map.prototype && new Map([[0, 0]]).size === 1 ? Map : undefined; } @@ -147,6 +148,7 @@ namespace NativeCollections { export function tryGetNativeSet(): SetConstructor | undefined { // Internet Explorer's Set doesn't support iteration, so don't use it. // eslint-disable-next-line no-in-operator + const Set = globalThis.Set as any; return typeof Set !== "undefined" && "entries" in Set.prototype && new Set([0]).size === 1 ? Set : undefined; } }
This code was picking up on the local versions of
MapandSetinstead of the global versions, so it was always installing the shim version and never using the native version. Using the nativeMapandSetis a 50% speedup. I assume you'll figure this out too if you haven't already, but I thought I'd save you the trouble in case it's helpful.Anyway just wanted to share this result and bug fix. It's totally up to you whether or not you use esbuild, so no pressure. I imagine there are concerns about wanting to dogfood the TypeScript compiler. I was actually surprised to see you trying out esbuild at all.
Edit: Oh yeah, also I shipped cross-module enum inlining in esbuild version 0.14.7 if you want to try it out.
Reacted by Daniel Rosenwasser, Elian Cordoba, Orta Therox, Harry Solovay, Ryan Cavanaugh, MORIYA Hiroyuki, mori yuta, Victorien Elvinger and GulshanReacted by Daniel Rosenwasser and Harry SolovayReacted by Daniel Rosenwasser and ExE BossDanielRosenwasser commented
on Dec 21, 2021 MemberAuthorMore actionsEvan Wallace (@evanw) you're a life-saver.
Eli Barzilay (@elibarzilay) can you experiment with the above? The only catch is that we don't always have
globalThisdefined in older JS versions, so I think you'll have to try something likeconst localGlobal = typeof globalThis !== "undefined" ? globalThis : typeof global !== "undefined" ? global : typeof window !== "undefined" ? window; const Map = localGlobal.Map as any;
DanielRosenwasser commented
on Dec 21, 2021 MemberAuthorMore actionsI think one other thing to consider is that this is something the conversion script kept working, but silently wrong. Seems like nested namespaces and places where we use local
declares might be something to watch out for.Reacted by ExE Bosselibarzilay commented
on Jan 12, 2022 ContributorMore actionsEvan Wallace (@evanw) Thanks for that and sorry that I got to it so late. I'm guessing that you were running esbuild directly on the TS sources--? I'm using it with the CJS output of the compiler, and that has some differences in runtime -- specifically, my concern was the time it takes to run the full set of TS tests... First, I didn't see any change when bumping the version (which is probably expected, given that it's the cjs output).
Second, the Map/Set bug didn't actually affect the cjs output since it doesn't create a global but uses
exports.Mapdirectly -- I did try at some point to run esbuild directly on the ts sources which was very slow, so I'm wondering if that could have caused some of the cost (especially if comes on top of the getter cost). In any case, it is definitely a bug, and I just opened #47409 for that.I'm guessing that you were running esbuild directly on the TS sources--?
Yes, that's correct. I did that because you need to run esbuild on the TS sources to take advantage of TS features such as enum inlining, so that's the fastest way to run the code.
Reacted by Eli Barzilay, ExE Boss and Victorien ElvingerRE: #38511
You can emulate this today with a self-import
Can you explain this with an example please? I don't fully understand how importing self can achieve the same thing as proposed.
This links to typing default exports - is that the real feature?
Apparently
export default: Type <thing>syntax was introducing so much syntax ambiguity that this request has been stalled (#3792). Withexport implementswe can type the default export without limitations mentioned there:export implements { default: number }; export default 1
DanielRosenwasser commented
on Jan 19, 2022 MemberAuthorMore actionsCan you explain this with an example please? I don't fully understand how importing self can achieve the same thing as proposed.
In theory you can write
import * as self from "./self.js" const _: ExpectedType = self;
Reacted by Mohsen AzimiReacted by ExE Boss
"Correlated Union Types"
#30581
We want to be able to feed the callback with the original value; but now
vis a union type andf's parameter type is an intersection; that's not precise forv, and that intersection now only acceptsnever.People have speculated that maybe we need existential types so that we can say "this function takes whatever type
vhas" and can feed it through.Can try to re-model this in the form of a re-indexed mapped type.
With some improvements of inference and apparent types, we can enable most of these cases - 2 improvements on the scale of what feel like bug fixes.
{ [P in K]: Foo<P> }[X] => Foo<X>This is a weird pattern. Would like to not have to teach people to write this.
Modules Migration Status Update
#46567
__createBindingsissue.Ensuring Modules Conform to a Type
#38511
export implements SomeTypethat