Closed
Description
"Correlated Union Types"
type NumberRecord = { kind: "n", v: number, f: (v: number) => void };
type StringRecord = { kind: "s", v: string, f: (v: string) => void };
type BooleanRecord = { kind: "b", v: boolean, f: (v: boolean) => void };
type UnionRecord = NumberRecord | StringRecord | BooleanRecord;
function processRecord(record: UnionRecord) {
record.f(record.v); // error!
// error msg in TS3.2 and below: can't call union of functions
// error msg in TS3.3 and up: record.v not assignable to never
}
-
We want to be able to feed the callback with the original value; but now
v
is 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
v
has" and can feed it through. -
Can try to re-model this in the form of a re-indexed mapped type.
interface TypeMap { "n": number; "s": string; "b": boolean; } type UnionRecord<P extends keyof TypeMap> = { [K in P}]: { kind: K; v: TypeMap[K]; f: (p: TypeMap[K]) => void; } }[K]; function processRecord<K extends keyof TypeMap>(record: UnionRecord<K>) { record.f(record.v); }
-
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.
- First is inference to the IIFE-like mapped object pattern from above.
- Second is how we present the apparent members of certain types when you index into an already-instantiated mapped object type (a "table type") with some generic key.
{ [P in K]: Foo<P> }[X] => Foo<X>
- Does that mean that if you aren't using a type that was declared as a mapped type, then we won't get a more precise type?
- Yes, if you leave off types on these objects.
- I guess we don't have an easy way to correlate.
- We could try to do something there...but that's a bit of a stretch.
- Yes, if you leave off types on these objects.
-
This is a weird pattern. Would like to not have to teach people to write this.
Modules Migration Status Update
- A lot of time running tests.
- A lot of time is going into getters for every single binding.
- Had TypeScript generate to CJS, had esbuild run on top of that.
- Swapped TS to generate ESM, and esbuild generates the same sorts of bindings - so no optimization there.
- 25 minutes to run the full tests! Thanks to the multiple levels of indirections of calling functions.
- Could switch to ES3 emit to avoid accessors.
- Also could switch to native ESM emit.
- No telling how slow ESM live bindings would be.
- Could avoid indirect barrel imports.
- Looked at bundler front-ends that are largely esbuild wrappers.
- But these tend to push for the optimized build to use Rollup.
- [[Whole discussion on what the right shipping format and layout to send.]]
- Dogfooding with modules showed us just how slow this is.
- Even getting complaints on tslib: __createBinding performance issue on web browsers tslib#165
- Conclusion
- Investigate the
__createBindings
issue. - Investigate alternative bundlers.
- Investigate the
Ensuring Modules Conform to a Type
- Lots of people would like to be able to ensure "this file has this sort of shape."
- Then "I would like this folder to describe this shape".
export implements SomeType
that- PR suggests everything should be contextually typed.
- You can emulate this today with a self-import.
- Without contextual typing, this is possibly just sugar that saves you 2 lines. Maybe not as compelling.
- This links to typing default exports - is that the real feature?
- Out of time - revisit in the new year.