mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Fix multiple issues with indexed access types applied to mapped types (#47109)
* Fix multiple issues with indexed access types applied to mapped types * Add tests
This commit is contained in:
+30
-19
@@ -12048,13 +12048,24 @@ namespace ts {
|
||||
return type;
|
||||
}
|
||||
|
||||
function isMappedTypeGenericIndexedAccess(type: Type) {
|
||||
return type.flags & TypeFlags.IndexedAccess && getObjectFlags((type as IndexedAccessType).objectType) & ObjectFlags.Mapped &&
|
||||
!isGenericMappedType((type as IndexedAccessType).objectType) && isGenericIndexType((type as IndexedAccessType).indexType);
|
||||
}
|
||||
|
||||
/**
|
||||
* For a type parameter, return the base constraint of the type parameter. For the string, number,
|
||||
* boolean, and symbol primitive types, return the corresponding object types. Otherwise return the
|
||||
* type itself.
|
||||
*/
|
||||
function getApparentType(type: Type): Type {
|
||||
const t = type.flags & TypeFlags.Instantiable ? getBaseConstraintOfType(type) || unknownType : type;
|
||||
// We obtain the base constraint for all instantiable types, except indexed access types of the form
|
||||
// { [P in K]: E }[X], where K is non-generic and X is generic. For those types, we instead substitute an
|
||||
// instantiation of E where P is replaced with X. We do this because getBaseConstraintOfType directly
|
||||
// lowers to an instantiation where X's constraint is substituted for X, which isn't always desirable.
|
||||
const t = !(type.flags & TypeFlags.Instantiable) ? type :
|
||||
isMappedTypeGenericIndexedAccess(type) ? substituteIndexedMappedType((type as IndexedAccessType).objectType as MappedType, (type as IndexedAccessType).indexType) :
|
||||
getBaseConstraintOfType(type) || unknownType;
|
||||
return getObjectFlags(t) & ObjectFlags.Mapped ? getApparentTypeOfMappedType(t as MappedType) :
|
||||
t.flags & TypeFlags.Intersection ? getApparentTypeOfIntersectionType(t as IntersectionType) :
|
||||
t.flags & TypeFlags.StringLike ? globalStringType :
|
||||
@@ -21845,12 +21856,14 @@ namespace ts {
|
||||
// not contain anyFunctionType when we come back to this argument for its second round
|
||||
// of inference. Also, we exclude inferences for silentNeverType (which is used as a wildcard
|
||||
// when constructing types from type parameters that had no inference candidates).
|
||||
if (getObjectFlags(source) & ObjectFlags.NonInferrableType || source === nonInferrableAnyType || source === silentNeverType ||
|
||||
(priority & InferencePriority.ReturnType && (source === autoType || source === autoArrayType)) || isFromInferenceBlockedSource(source)) {
|
||||
if (source === nonInferrableAnyType || source === silentNeverType || (priority & InferencePriority.ReturnType && (source === autoType || source === autoArrayType)) || isFromInferenceBlockedSource(source)) {
|
||||
return;
|
||||
}
|
||||
const inference = getInferenceInfoForType(target);
|
||||
if (inference) {
|
||||
if (getObjectFlags(source) & ObjectFlags.NonInferrableType) {
|
||||
return;
|
||||
}
|
||||
if (!inference.isFixed) {
|
||||
if (inference.priority === undefined || priority < inference.priority) {
|
||||
inference.candidates = undefined;
|
||||
@@ -21881,21 +21894,19 @@ namespace ts {
|
||||
inferencePriority = Math.min(inferencePriority, priority);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
// Infer to the simplified version of an indexed access, if possible, to (hopefully) expose more bare type parameters to the inference engine
|
||||
const simplified = getSimplifiedType(target, /*writing*/ false);
|
||||
if (simplified !== target) {
|
||||
invokeOnce(source, simplified, inferFromTypes);
|
||||
}
|
||||
else if (target.flags & TypeFlags.IndexedAccess) {
|
||||
const indexType = getSimplifiedType((target as IndexedAccessType).indexType, /*writing*/ false);
|
||||
// Generally simplifications of instantiable indexes are avoided to keep relationship checking correct, however if our target is an access, we can consider
|
||||
// that key of that access to be "instantiated", since we're looking to find the infernce goal in any way we can.
|
||||
if (indexType.flags & TypeFlags.Instantiable) {
|
||||
const simplified = distributeIndexOverObjectType(getSimplifiedType((target as IndexedAccessType).objectType, /*writing*/ false), indexType, /*writing*/ false);
|
||||
if (simplified && simplified !== target) {
|
||||
invokeOnce(source, simplified, inferFromTypes);
|
||||
}
|
||||
// Infer to the simplified version of an indexed access, if possible, to (hopefully) expose more bare type parameters to the inference engine
|
||||
const simplified = getSimplifiedType(target, /*writing*/ false);
|
||||
if (simplified !== target) {
|
||||
inferFromTypes(source, simplified);
|
||||
}
|
||||
else if (target.flags & TypeFlags.IndexedAccess) {
|
||||
const indexType = getSimplifiedType((target as IndexedAccessType).indexType, /*writing*/ false);
|
||||
// Generally simplifications of instantiable indexes are avoided to keep relationship checking correct, however if our target is an access, we can consider
|
||||
// that key of that access to be "instantiated", since we're looking to find the infernce goal in any way we can.
|
||||
if (indexType.flags & TypeFlags.Instantiable) {
|
||||
const simplified = distributeIndexOverObjectType(getSimplifiedType((target as IndexedAccessType).objectType, /*writing*/ false), indexType, /*writing*/ false);
|
||||
if (simplified && simplified !== target) {
|
||||
inferFromTypes(source, simplified);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24929,7 +24940,7 @@ namespace ts {
|
||||
const substituteConstraints = !(checkMode && checkMode & CheckMode.Inferential) &&
|
||||
someType(type, isGenericTypeWithUnionConstraint) &&
|
||||
(isConstraintPosition(type, reference) || hasNonBindingPatternContextualTypeWithNoGenericTypes(reference));
|
||||
return substituteConstraints ? mapType(type, t => t.flags & TypeFlags.Instantiable ? getBaseConstraintOrType(t) : t) : type;
|
||||
return substituteConstraints ? mapType(type, t => t.flags & TypeFlags.Instantiable && !isMappedTypeGenericIndexedAccess(t) ? getBaseConstraintOrType(t) : t) : type;
|
||||
}
|
||||
|
||||
function isExportOrExportExpression(location: Node) {
|
||||
|
||||
@@ -0,0 +1,350 @@
|
||||
//// [correlatedUnions.ts]
|
||||
// Various repros from #30581
|
||||
|
||||
type RecordMap = { n: number, s: string, b: boolean };
|
||||
type UnionRecord<K extends keyof RecordMap = keyof RecordMap> = { [P in K]: {
|
||||
kind: P,
|
||||
v: RecordMap[P],
|
||||
f: (v: RecordMap[P]) => void
|
||||
}}[K];
|
||||
|
||||
function processRecord<K extends keyof RecordMap>(rec: UnionRecord<K>) {
|
||||
rec.f(rec.v);
|
||||
}
|
||||
|
||||
declare const r1: UnionRecord<'n'>; // { kind: 'n', v: number, f: (v: number) => void }
|
||||
declare const r2: UnionRecord; // { kind: 'n', ... } | { kind: 's', ... } | { kind: 'b', ... }
|
||||
|
||||
processRecord(r1);
|
||||
processRecord(r2);
|
||||
processRecord({ kind: 'n', v: 42, f: v => v.toExponential() });
|
||||
|
||||
// --------
|
||||
|
||||
type TextFieldData = { value: string }
|
||||
type SelectFieldData = { options: string[], selectedValue: string }
|
||||
|
||||
type FieldMap = {
|
||||
text: TextFieldData;
|
||||
select: SelectFieldData;
|
||||
}
|
||||
|
||||
type FormField<K extends keyof FieldMap> = { type: K, data: FieldMap[K] };
|
||||
|
||||
type RenderFunc<K extends keyof FieldMap> = (props: FieldMap[K]) => void;
|
||||
type RenderFuncMap = { [K in keyof FieldMap]: RenderFunc<K> };
|
||||
|
||||
function renderTextField(props: TextFieldData) {}
|
||||
function renderSelectField(props: SelectFieldData) {}
|
||||
|
||||
const renderFuncs: RenderFuncMap = {
|
||||
text: renderTextField,
|
||||
select: renderSelectField,
|
||||
};
|
||||
|
||||
function renderField<K extends keyof FieldMap>(field: FormField<K>) {
|
||||
const renderFn = renderFuncs[field.type];
|
||||
renderFn(field.data);
|
||||
}
|
||||
|
||||
// --------
|
||||
|
||||
type TypeMap = {
|
||||
foo: string,
|
||||
bar: number
|
||||
};
|
||||
|
||||
type Keys = keyof TypeMap;
|
||||
|
||||
type HandlerMap = { [P in Keys]: (x: TypeMap[P]) => void };
|
||||
|
||||
const handlers: HandlerMap = {
|
||||
foo: s => s.length,
|
||||
bar: n => n.toFixed(2)
|
||||
};
|
||||
|
||||
type DataEntry<K extends Keys = Keys> = { [P in K]: {
|
||||
type: P,
|
||||
data: TypeMap[P]
|
||||
}}[K];
|
||||
|
||||
const data: DataEntry[] = [
|
||||
{ type: 'foo', data: 'abc' },
|
||||
{ type: 'foo', data: 'def' },
|
||||
{ type: 'bar', data: 42 },
|
||||
];
|
||||
|
||||
function process<K extends Keys>(data: DataEntry<K>[]) {
|
||||
data.forEach(block => {
|
||||
if (block.type in handlers) {
|
||||
handlers[block.type](block.data)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
process(data);
|
||||
process([{ type: 'foo', data: 'abc' }]);
|
||||
|
||||
// --------
|
||||
|
||||
type LetterMap = { A: string, B: number }
|
||||
type LetterCaller<K extends keyof LetterMap> = { [P in K]: { letter: Record<P, LetterMap[P]>, caller: (x: Record<P, LetterMap[P]>) => void } }[K];
|
||||
|
||||
function call<K extends keyof LetterMap>({ letter, caller }: LetterCaller<K>): void {
|
||||
caller(letter);
|
||||
}
|
||||
|
||||
type A = { A: string };
|
||||
type B = { B: number };
|
||||
type ACaller = (a: A) => void;
|
||||
type BCaller = (b: B) => void;
|
||||
|
||||
declare const xx: { letter: A, caller: ACaller } | { letter: B, caller: BCaller };
|
||||
|
||||
call(xx);
|
||||
|
||||
// --------
|
||||
|
||||
type Ev<K extends keyof DocumentEventMap> = { [P in K]: {
|
||||
readonly name: P;
|
||||
readonly once?: boolean;
|
||||
readonly callback: (ev: DocumentEventMap[P]) => void;
|
||||
}}[K];
|
||||
|
||||
function processEvents<K extends keyof DocumentEventMap>(events: Ev<K>[]) {
|
||||
for (const event of events) {
|
||||
document.addEventListener(event.name, (ev) => event.callback(ev), { once: event.once });
|
||||
}
|
||||
}
|
||||
|
||||
function createEventListener<K extends keyof DocumentEventMap>({ name, once = false, callback }: Ev<K>): Ev<K> {
|
||||
return { name, once, callback };
|
||||
}
|
||||
|
||||
const clickEvent = createEventListener({
|
||||
name: "click",
|
||||
callback: ev => console.log(ev),
|
||||
});
|
||||
|
||||
const scrollEvent = createEventListener({
|
||||
name: "scroll",
|
||||
callback: ev => console.log(ev),
|
||||
});
|
||||
|
||||
processEvents([clickEvent, scrollEvent]);
|
||||
|
||||
processEvents([
|
||||
{ name: "click", callback: ev => console.log(ev) },
|
||||
{ name: "scroll", callback: ev => console.log(ev) },
|
||||
]);
|
||||
|
||||
// --------
|
||||
|
||||
function ff1() {
|
||||
type ArgMap = {
|
||||
sum: [a: number, b: number],
|
||||
concat: [a: string, b: string, c: string]
|
||||
}
|
||||
type Keys = keyof ArgMap;
|
||||
const funs: { [P in Keys]: (...args: ArgMap[P]) => void } = {
|
||||
sum: (a, b) => a + b,
|
||||
concat: (a, b, c) => a + b + c
|
||||
}
|
||||
function apply<K extends Keys>(funKey: K, ...args: ArgMap[K]) {
|
||||
const fn = funs[funKey];
|
||||
fn(...args);
|
||||
}
|
||||
const x1 = apply('sum', 1, 2)
|
||||
const x2 = apply('concat', 'str1', 'str2', 'str3' )
|
||||
}
|
||||
|
||||
|
||||
//// [correlatedUnions.js]
|
||||
"use strict";
|
||||
// Various repros from #30581
|
||||
function processRecord(rec) {
|
||||
rec.f(rec.v);
|
||||
}
|
||||
processRecord(r1);
|
||||
processRecord(r2);
|
||||
processRecord({ kind: 'n', v: 42, f: function (v) { return v.toExponential(); } });
|
||||
function renderTextField(props) { }
|
||||
function renderSelectField(props) { }
|
||||
var renderFuncs = {
|
||||
text: renderTextField,
|
||||
select: renderSelectField
|
||||
};
|
||||
function renderField(field) {
|
||||
var renderFn = renderFuncs[field.type];
|
||||
renderFn(field.data);
|
||||
}
|
||||
var handlers = {
|
||||
foo: function (s) { return s.length; },
|
||||
bar: function (n) { return n.toFixed(2); }
|
||||
};
|
||||
var data = [
|
||||
{ type: 'foo', data: 'abc' },
|
||||
{ type: 'foo', data: 'def' },
|
||||
{ type: 'bar', data: 42 },
|
||||
];
|
||||
function process(data) {
|
||||
data.forEach(function (block) {
|
||||
if (block.type in handlers) {
|
||||
handlers[block.type](block.data);
|
||||
}
|
||||
});
|
||||
}
|
||||
process(data);
|
||||
process([{ type: 'foo', data: 'abc' }]);
|
||||
function call(_a) {
|
||||
var letter = _a.letter, caller = _a.caller;
|
||||
caller(letter);
|
||||
}
|
||||
call(xx);
|
||||
function processEvents(events) {
|
||||
var _loop_1 = function (event_1) {
|
||||
document.addEventListener(event_1.name, function (ev) { return event_1.callback(ev); }, { once: event_1.once });
|
||||
};
|
||||
for (var _i = 0, events_1 = events; _i < events_1.length; _i++) {
|
||||
var event_1 = events_1[_i];
|
||||
_loop_1(event_1);
|
||||
}
|
||||
}
|
||||
function createEventListener(_a) {
|
||||
var name = _a.name, _b = _a.once, once = _b === void 0 ? false : _b, callback = _a.callback;
|
||||
return { name: name, once: once, callback: callback };
|
||||
}
|
||||
var clickEvent = createEventListener({
|
||||
name: "click",
|
||||
callback: function (ev) { return console.log(ev); }
|
||||
});
|
||||
var scrollEvent = createEventListener({
|
||||
name: "scroll",
|
||||
callback: function (ev) { return console.log(ev); }
|
||||
});
|
||||
processEvents([clickEvent, scrollEvent]);
|
||||
processEvents([
|
||||
{ name: "click", callback: function (ev) { return console.log(ev); } },
|
||||
{ name: "scroll", callback: function (ev) { return console.log(ev); } },
|
||||
]);
|
||||
// --------
|
||||
function ff1() {
|
||||
var funs = {
|
||||
sum: function (a, b) { return a + b; },
|
||||
concat: function (a, b, c) { return a + b + c; }
|
||||
};
|
||||
function apply(funKey) {
|
||||
var args = [];
|
||||
for (var _i = 1; _i < arguments.length; _i++) {
|
||||
args[_i - 1] = arguments[_i];
|
||||
}
|
||||
var fn = funs[funKey];
|
||||
fn.apply(void 0, args);
|
||||
}
|
||||
var x1 = apply('sum', 1, 2);
|
||||
var x2 = apply('concat', 'str1', 'str2', 'str3');
|
||||
}
|
||||
|
||||
|
||||
//// [correlatedUnions.d.ts]
|
||||
declare type RecordMap = {
|
||||
n: number;
|
||||
s: string;
|
||||
b: boolean;
|
||||
};
|
||||
declare type UnionRecord<K extends keyof RecordMap = keyof RecordMap> = {
|
||||
[P in K]: {
|
||||
kind: P;
|
||||
v: RecordMap[P];
|
||||
f: (v: RecordMap[P]) => void;
|
||||
};
|
||||
}[K];
|
||||
declare function processRecord<K extends keyof RecordMap>(rec: UnionRecord<K>): void;
|
||||
declare const r1: UnionRecord<'n'>;
|
||||
declare const r2: UnionRecord;
|
||||
declare type TextFieldData = {
|
||||
value: string;
|
||||
};
|
||||
declare type SelectFieldData = {
|
||||
options: string[];
|
||||
selectedValue: string;
|
||||
};
|
||||
declare type FieldMap = {
|
||||
text: TextFieldData;
|
||||
select: SelectFieldData;
|
||||
};
|
||||
declare type FormField<K extends keyof FieldMap> = {
|
||||
type: K;
|
||||
data: FieldMap[K];
|
||||
};
|
||||
declare type RenderFunc<K extends keyof FieldMap> = (props: FieldMap[K]) => void;
|
||||
declare type RenderFuncMap = {
|
||||
[K in keyof FieldMap]: RenderFunc<K>;
|
||||
};
|
||||
declare function renderTextField(props: TextFieldData): void;
|
||||
declare function renderSelectField(props: SelectFieldData): void;
|
||||
declare const renderFuncs: RenderFuncMap;
|
||||
declare function renderField<K extends keyof FieldMap>(field: FormField<K>): void;
|
||||
declare type TypeMap = {
|
||||
foo: string;
|
||||
bar: number;
|
||||
};
|
||||
declare type Keys = keyof TypeMap;
|
||||
declare type HandlerMap = {
|
||||
[P in Keys]: (x: TypeMap[P]) => void;
|
||||
};
|
||||
declare const handlers: HandlerMap;
|
||||
declare type DataEntry<K extends Keys = Keys> = {
|
||||
[P in K]: {
|
||||
type: P;
|
||||
data: TypeMap[P];
|
||||
};
|
||||
}[K];
|
||||
declare const data: DataEntry[];
|
||||
declare function process<K extends Keys>(data: DataEntry<K>[]): void;
|
||||
declare type LetterMap = {
|
||||
A: string;
|
||||
B: number;
|
||||
};
|
||||
declare type LetterCaller<K extends keyof LetterMap> = {
|
||||
[P in K]: {
|
||||
letter: Record<P, LetterMap[P]>;
|
||||
caller: (x: Record<P, LetterMap[P]>) => void;
|
||||
};
|
||||
}[K];
|
||||
declare function call<K extends keyof LetterMap>({ letter, caller }: LetterCaller<K>): void;
|
||||
declare type A = {
|
||||
A: string;
|
||||
};
|
||||
declare type B = {
|
||||
B: number;
|
||||
};
|
||||
declare type ACaller = (a: A) => void;
|
||||
declare type BCaller = (b: B) => void;
|
||||
declare const xx: {
|
||||
letter: A;
|
||||
caller: ACaller;
|
||||
} | {
|
||||
letter: B;
|
||||
caller: BCaller;
|
||||
};
|
||||
declare type Ev<K extends keyof DocumentEventMap> = {
|
||||
[P in K]: {
|
||||
readonly name: P;
|
||||
readonly once?: boolean;
|
||||
readonly callback: (ev: DocumentEventMap[P]) => void;
|
||||
};
|
||||
}[K];
|
||||
declare function processEvents<K extends keyof DocumentEventMap>(events: Ev<K>[]): void;
|
||||
declare function createEventListener<K extends keyof DocumentEventMap>({ name, once, callback }: Ev<K>): Ev<K>;
|
||||
declare const clickEvent: {
|
||||
readonly name: "click";
|
||||
readonly once?: boolean | undefined;
|
||||
readonly callback: (ev: MouseEvent) => void;
|
||||
};
|
||||
declare const scrollEvent: {
|
||||
readonly name: "scroll";
|
||||
readonly once?: boolean | undefined;
|
||||
readonly callback: (ev: Event) => void;
|
||||
};
|
||||
declare function ff1(): void;
|
||||
@@ -0,0 +1,575 @@
|
||||
=== tests/cases/compiler/correlatedUnions.ts ===
|
||||
// Various repros from #30581
|
||||
|
||||
type RecordMap = { n: number, s: string, b: boolean };
|
||||
>RecordMap : Symbol(RecordMap, Decl(correlatedUnions.ts, 0, 0))
|
||||
>n : Symbol(n, Decl(correlatedUnions.ts, 2, 18))
|
||||
>s : Symbol(s, Decl(correlatedUnions.ts, 2, 29))
|
||||
>b : Symbol(b, Decl(correlatedUnions.ts, 2, 40))
|
||||
|
||||
type UnionRecord<K extends keyof RecordMap = keyof RecordMap> = { [P in K]: {
|
||||
>UnionRecord : Symbol(UnionRecord, Decl(correlatedUnions.ts, 2, 54))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 3, 17))
|
||||
>RecordMap : Symbol(RecordMap, Decl(correlatedUnions.ts, 0, 0))
|
||||
>RecordMap : Symbol(RecordMap, Decl(correlatedUnions.ts, 0, 0))
|
||||
>P : Symbol(P, Decl(correlatedUnions.ts, 3, 67))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 3, 17))
|
||||
|
||||
kind: P,
|
||||
>kind : Symbol(kind, Decl(correlatedUnions.ts, 3, 77))
|
||||
>P : Symbol(P, Decl(correlatedUnions.ts, 3, 67))
|
||||
|
||||
v: RecordMap[P],
|
||||
>v : Symbol(v, Decl(correlatedUnions.ts, 4, 12))
|
||||
>RecordMap : Symbol(RecordMap, Decl(correlatedUnions.ts, 0, 0))
|
||||
>P : Symbol(P, Decl(correlatedUnions.ts, 3, 67))
|
||||
|
||||
f: (v: RecordMap[P]) => void
|
||||
>f : Symbol(f, Decl(correlatedUnions.ts, 5, 20))
|
||||
>v : Symbol(v, Decl(correlatedUnions.ts, 6, 8))
|
||||
>RecordMap : Symbol(RecordMap, Decl(correlatedUnions.ts, 0, 0))
|
||||
>P : Symbol(P, Decl(correlatedUnions.ts, 3, 67))
|
||||
|
||||
}}[K];
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 3, 17))
|
||||
|
||||
function processRecord<K extends keyof RecordMap>(rec: UnionRecord<K>) {
|
||||
>processRecord : Symbol(processRecord, Decl(correlatedUnions.ts, 7, 6))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 9, 23))
|
||||
>RecordMap : Symbol(RecordMap, Decl(correlatedUnions.ts, 0, 0))
|
||||
>rec : Symbol(rec, Decl(correlatedUnions.ts, 9, 50))
|
||||
>UnionRecord : Symbol(UnionRecord, Decl(correlatedUnions.ts, 2, 54))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 9, 23))
|
||||
|
||||
rec.f(rec.v);
|
||||
>rec.f : Symbol(f, Decl(correlatedUnions.ts, 5, 20))
|
||||
>rec : Symbol(rec, Decl(correlatedUnions.ts, 9, 50))
|
||||
>f : Symbol(f, Decl(correlatedUnions.ts, 5, 20))
|
||||
>rec.v : Symbol(v, Decl(correlatedUnions.ts, 4, 12))
|
||||
>rec : Symbol(rec, Decl(correlatedUnions.ts, 9, 50))
|
||||
>v : Symbol(v, Decl(correlatedUnions.ts, 4, 12))
|
||||
}
|
||||
|
||||
declare const r1: UnionRecord<'n'>; // { kind: 'n', v: number, f: (v: number) => void }
|
||||
>r1 : Symbol(r1, Decl(correlatedUnions.ts, 13, 13))
|
||||
>UnionRecord : Symbol(UnionRecord, Decl(correlatedUnions.ts, 2, 54))
|
||||
|
||||
declare const r2: UnionRecord; // { kind: 'n', ... } | { kind: 's', ... } | { kind: 'b', ... }
|
||||
>r2 : Symbol(r2, Decl(correlatedUnions.ts, 14, 13))
|
||||
>UnionRecord : Symbol(UnionRecord, Decl(correlatedUnions.ts, 2, 54))
|
||||
|
||||
processRecord(r1);
|
||||
>processRecord : Symbol(processRecord, Decl(correlatedUnions.ts, 7, 6))
|
||||
>r1 : Symbol(r1, Decl(correlatedUnions.ts, 13, 13))
|
||||
|
||||
processRecord(r2);
|
||||
>processRecord : Symbol(processRecord, Decl(correlatedUnions.ts, 7, 6))
|
||||
>r2 : Symbol(r2, Decl(correlatedUnions.ts, 14, 13))
|
||||
|
||||
processRecord({ kind: 'n', v: 42, f: v => v.toExponential() });
|
||||
>processRecord : Symbol(processRecord, Decl(correlatedUnions.ts, 7, 6))
|
||||
>kind : Symbol(kind, Decl(correlatedUnions.ts, 18, 15))
|
||||
>v : Symbol(v, Decl(correlatedUnions.ts, 18, 26))
|
||||
>f : Symbol(f, Decl(correlatedUnions.ts, 18, 33))
|
||||
>v : Symbol(v, Decl(correlatedUnions.ts, 18, 36))
|
||||
>v.toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
|
||||
>v : Symbol(v, Decl(correlatedUnions.ts, 18, 36))
|
||||
>toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
// --------
|
||||
|
||||
type TextFieldData = { value: string }
|
||||
>TextFieldData : Symbol(TextFieldData, Decl(correlatedUnions.ts, 18, 63))
|
||||
>value : Symbol(value, Decl(correlatedUnions.ts, 22, 22))
|
||||
|
||||
type SelectFieldData = { options: string[], selectedValue: string }
|
||||
>SelectFieldData : Symbol(SelectFieldData, Decl(correlatedUnions.ts, 22, 38))
|
||||
>options : Symbol(options, Decl(correlatedUnions.ts, 23, 24))
|
||||
>selectedValue : Symbol(selectedValue, Decl(correlatedUnions.ts, 23, 43))
|
||||
|
||||
type FieldMap = {
|
||||
>FieldMap : Symbol(FieldMap, Decl(correlatedUnions.ts, 23, 67))
|
||||
|
||||
text: TextFieldData;
|
||||
>text : Symbol(text, Decl(correlatedUnions.ts, 25, 17))
|
||||
>TextFieldData : Symbol(TextFieldData, Decl(correlatedUnions.ts, 18, 63))
|
||||
|
||||
select: SelectFieldData;
|
||||
>select : Symbol(select, Decl(correlatedUnions.ts, 26, 24))
|
||||
>SelectFieldData : Symbol(SelectFieldData, Decl(correlatedUnions.ts, 22, 38))
|
||||
}
|
||||
|
||||
type FormField<K extends keyof FieldMap> = { type: K, data: FieldMap[K] };
|
||||
>FormField : Symbol(FormField, Decl(correlatedUnions.ts, 28, 1))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 30, 15))
|
||||
>FieldMap : Symbol(FieldMap, Decl(correlatedUnions.ts, 23, 67))
|
||||
>type : Symbol(type, Decl(correlatedUnions.ts, 30, 44))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 30, 15))
|
||||
>data : Symbol(data, Decl(correlatedUnions.ts, 30, 53))
|
||||
>FieldMap : Symbol(FieldMap, Decl(correlatedUnions.ts, 23, 67))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 30, 15))
|
||||
|
||||
type RenderFunc<K extends keyof FieldMap> = (props: FieldMap[K]) => void;
|
||||
>RenderFunc : Symbol(RenderFunc, Decl(correlatedUnions.ts, 30, 74))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 32, 16))
|
||||
>FieldMap : Symbol(FieldMap, Decl(correlatedUnions.ts, 23, 67))
|
||||
>props : Symbol(props, Decl(correlatedUnions.ts, 32, 45))
|
||||
>FieldMap : Symbol(FieldMap, Decl(correlatedUnions.ts, 23, 67))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 32, 16))
|
||||
|
||||
type RenderFuncMap = { [K in keyof FieldMap]: RenderFunc<K> };
|
||||
>RenderFuncMap : Symbol(RenderFuncMap, Decl(correlatedUnions.ts, 32, 73))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 33, 24))
|
||||
>FieldMap : Symbol(FieldMap, Decl(correlatedUnions.ts, 23, 67))
|
||||
>RenderFunc : Symbol(RenderFunc, Decl(correlatedUnions.ts, 30, 74))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 33, 24))
|
||||
|
||||
function renderTextField(props: TextFieldData) {}
|
||||
>renderTextField : Symbol(renderTextField, Decl(correlatedUnions.ts, 33, 62))
|
||||
>props : Symbol(props, Decl(correlatedUnions.ts, 35, 25))
|
||||
>TextFieldData : Symbol(TextFieldData, Decl(correlatedUnions.ts, 18, 63))
|
||||
|
||||
function renderSelectField(props: SelectFieldData) {}
|
||||
>renderSelectField : Symbol(renderSelectField, Decl(correlatedUnions.ts, 35, 49))
|
||||
>props : Symbol(props, Decl(correlatedUnions.ts, 36, 27))
|
||||
>SelectFieldData : Symbol(SelectFieldData, Decl(correlatedUnions.ts, 22, 38))
|
||||
|
||||
const renderFuncs: RenderFuncMap = {
|
||||
>renderFuncs : Symbol(renderFuncs, Decl(correlatedUnions.ts, 38, 5))
|
||||
>RenderFuncMap : Symbol(RenderFuncMap, Decl(correlatedUnions.ts, 32, 73))
|
||||
|
||||
text: renderTextField,
|
||||
>text : Symbol(text, Decl(correlatedUnions.ts, 38, 36))
|
||||
>renderTextField : Symbol(renderTextField, Decl(correlatedUnions.ts, 33, 62))
|
||||
|
||||
select: renderSelectField,
|
||||
>select : Symbol(select, Decl(correlatedUnions.ts, 39, 26))
|
||||
>renderSelectField : Symbol(renderSelectField, Decl(correlatedUnions.ts, 35, 49))
|
||||
|
||||
};
|
||||
|
||||
function renderField<K extends keyof FieldMap>(field: FormField<K>) {
|
||||
>renderField : Symbol(renderField, Decl(correlatedUnions.ts, 41, 2))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 43, 21))
|
||||
>FieldMap : Symbol(FieldMap, Decl(correlatedUnions.ts, 23, 67))
|
||||
>field : Symbol(field, Decl(correlatedUnions.ts, 43, 47))
|
||||
>FormField : Symbol(FormField, Decl(correlatedUnions.ts, 28, 1))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 43, 21))
|
||||
|
||||
const renderFn = renderFuncs[field.type];
|
||||
>renderFn : Symbol(renderFn, Decl(correlatedUnions.ts, 44, 9))
|
||||
>renderFuncs : Symbol(renderFuncs, Decl(correlatedUnions.ts, 38, 5))
|
||||
>field.type : Symbol(type, Decl(correlatedUnions.ts, 30, 44))
|
||||
>field : Symbol(field, Decl(correlatedUnions.ts, 43, 47))
|
||||
>type : Symbol(type, Decl(correlatedUnions.ts, 30, 44))
|
||||
|
||||
renderFn(field.data);
|
||||
>renderFn : Symbol(renderFn, Decl(correlatedUnions.ts, 44, 9))
|
||||
>field.data : Symbol(data, Decl(correlatedUnions.ts, 30, 53))
|
||||
>field : Symbol(field, Decl(correlatedUnions.ts, 43, 47))
|
||||
>data : Symbol(data, Decl(correlatedUnions.ts, 30, 53))
|
||||
}
|
||||
|
||||
// --------
|
||||
|
||||
type TypeMap = {
|
||||
>TypeMap : Symbol(TypeMap, Decl(correlatedUnions.ts, 46, 1))
|
||||
|
||||
foo: string,
|
||||
>foo : Symbol(foo, Decl(correlatedUnions.ts, 50, 16))
|
||||
|
||||
bar: number
|
||||
>bar : Symbol(bar, Decl(correlatedUnions.ts, 51, 16))
|
||||
|
||||
};
|
||||
|
||||
type Keys = keyof TypeMap;
|
||||
>Keys : Symbol(Keys, Decl(correlatedUnions.ts, 53, 2))
|
||||
>TypeMap : Symbol(TypeMap, Decl(correlatedUnions.ts, 46, 1))
|
||||
|
||||
type HandlerMap = { [P in Keys]: (x: TypeMap[P]) => void };
|
||||
>HandlerMap : Symbol(HandlerMap, Decl(correlatedUnions.ts, 55, 26))
|
||||
>P : Symbol(P, Decl(correlatedUnions.ts, 57, 21))
|
||||
>Keys : Symbol(Keys, Decl(correlatedUnions.ts, 53, 2))
|
||||
>x : Symbol(x, Decl(correlatedUnions.ts, 57, 34))
|
||||
>TypeMap : Symbol(TypeMap, Decl(correlatedUnions.ts, 46, 1))
|
||||
>P : Symbol(P, Decl(correlatedUnions.ts, 57, 21))
|
||||
|
||||
const handlers: HandlerMap = {
|
||||
>handlers : Symbol(handlers, Decl(correlatedUnions.ts, 59, 5))
|
||||
>HandlerMap : Symbol(HandlerMap, Decl(correlatedUnions.ts, 55, 26))
|
||||
|
||||
foo: s => s.length,
|
||||
>foo : Symbol(foo, Decl(correlatedUnions.ts, 59, 30))
|
||||
>s : Symbol(s, Decl(correlatedUnions.ts, 60, 8))
|
||||
>s.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
|
||||
>s : Symbol(s, Decl(correlatedUnions.ts, 60, 8))
|
||||
>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
bar: n => n.toFixed(2)
|
||||
>bar : Symbol(bar, Decl(correlatedUnions.ts, 60, 23))
|
||||
>n : Symbol(n, Decl(correlatedUnions.ts, 61, 8))
|
||||
>n.toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --))
|
||||
>n : Symbol(n, Decl(correlatedUnions.ts, 61, 8))
|
||||
>toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
};
|
||||
|
||||
type DataEntry<K extends Keys = Keys> = { [P in K]: {
|
||||
>DataEntry : Symbol(DataEntry, Decl(correlatedUnions.ts, 62, 2))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 64, 15))
|
||||
>Keys : Symbol(Keys, Decl(correlatedUnions.ts, 53, 2))
|
||||
>Keys : Symbol(Keys, Decl(correlatedUnions.ts, 53, 2))
|
||||
>P : Symbol(P, Decl(correlatedUnions.ts, 64, 43))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 64, 15))
|
||||
|
||||
type: P,
|
||||
>type : Symbol(type, Decl(correlatedUnions.ts, 64, 53))
|
||||
>P : Symbol(P, Decl(correlatedUnions.ts, 64, 43))
|
||||
|
||||
data: TypeMap[P]
|
||||
>data : Symbol(data, Decl(correlatedUnions.ts, 65, 12))
|
||||
>TypeMap : Symbol(TypeMap, Decl(correlatedUnions.ts, 46, 1))
|
||||
>P : Symbol(P, Decl(correlatedUnions.ts, 64, 43))
|
||||
|
||||
}}[K];
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 64, 15))
|
||||
|
||||
const data: DataEntry[] = [
|
||||
>data : Symbol(data, Decl(correlatedUnions.ts, 69, 5))
|
||||
>DataEntry : Symbol(DataEntry, Decl(correlatedUnions.ts, 62, 2))
|
||||
|
||||
{ type: 'foo', data: 'abc' },
|
||||
>type : Symbol(type, Decl(correlatedUnions.ts, 70, 5))
|
||||
>data : Symbol(data, Decl(correlatedUnions.ts, 70, 18))
|
||||
|
||||
{ type: 'foo', data: 'def' },
|
||||
>type : Symbol(type, Decl(correlatedUnions.ts, 71, 5))
|
||||
>data : Symbol(data, Decl(correlatedUnions.ts, 71, 18))
|
||||
|
||||
{ type: 'bar', data: 42 },
|
||||
>type : Symbol(type, Decl(correlatedUnions.ts, 72, 5))
|
||||
>data : Symbol(data, Decl(correlatedUnions.ts, 72, 18))
|
||||
|
||||
];
|
||||
|
||||
function process<K extends Keys>(data: DataEntry<K>[]) {
|
||||
>process : Symbol(process, Decl(correlatedUnions.ts, 73, 2))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 75, 17))
|
||||
>Keys : Symbol(Keys, Decl(correlatedUnions.ts, 53, 2))
|
||||
>data : Symbol(data, Decl(correlatedUnions.ts, 75, 33))
|
||||
>DataEntry : Symbol(DataEntry, Decl(correlatedUnions.ts, 62, 2))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 75, 17))
|
||||
|
||||
data.forEach(block => {
|
||||
>data.forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --))
|
||||
>data : Symbol(data, Decl(correlatedUnions.ts, 75, 33))
|
||||
>forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --))
|
||||
>block : Symbol(block, Decl(correlatedUnions.ts, 76, 17))
|
||||
|
||||
if (block.type in handlers) {
|
||||
>block.type : Symbol(type, Decl(correlatedUnions.ts, 64, 53))
|
||||
>block : Symbol(block, Decl(correlatedUnions.ts, 76, 17))
|
||||
>type : Symbol(type, Decl(correlatedUnions.ts, 64, 53))
|
||||
>handlers : Symbol(handlers, Decl(correlatedUnions.ts, 59, 5))
|
||||
|
||||
handlers[block.type](block.data)
|
||||
>handlers : Symbol(handlers, Decl(correlatedUnions.ts, 59, 5))
|
||||
>block.type : Symbol(type, Decl(correlatedUnions.ts, 64, 53))
|
||||
>block : Symbol(block, Decl(correlatedUnions.ts, 76, 17))
|
||||
>type : Symbol(type, Decl(correlatedUnions.ts, 64, 53))
|
||||
>block.data : Symbol(data, Decl(correlatedUnions.ts, 65, 12))
|
||||
>block : Symbol(block, Decl(correlatedUnions.ts, 76, 17))
|
||||
>data : Symbol(data, Decl(correlatedUnions.ts, 65, 12))
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
process(data);
|
||||
>process : Symbol(process, Decl(correlatedUnions.ts, 73, 2))
|
||||
>data : Symbol(data, Decl(correlatedUnions.ts, 69, 5))
|
||||
|
||||
process([{ type: 'foo', data: 'abc' }]);
|
||||
>process : Symbol(process, Decl(correlatedUnions.ts, 73, 2))
|
||||
>type : Symbol(type, Decl(correlatedUnions.ts, 84, 10))
|
||||
>data : Symbol(data, Decl(correlatedUnions.ts, 84, 23))
|
||||
|
||||
// --------
|
||||
|
||||
type LetterMap = { A: string, B: number }
|
||||
>LetterMap : Symbol(LetterMap, Decl(correlatedUnions.ts, 84, 40))
|
||||
>A : Symbol(A, Decl(correlatedUnions.ts, 88, 18))
|
||||
>B : Symbol(B, Decl(correlatedUnions.ts, 88, 29))
|
||||
|
||||
type LetterCaller<K extends keyof LetterMap> = { [P in K]: { letter: Record<P, LetterMap[P]>, caller: (x: Record<P, LetterMap[P]>) => void } }[K];
|
||||
>LetterCaller : Symbol(LetterCaller, Decl(correlatedUnions.ts, 88, 41))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 89, 18))
|
||||
>LetterMap : Symbol(LetterMap, Decl(correlatedUnions.ts, 84, 40))
|
||||
>P : Symbol(P, Decl(correlatedUnions.ts, 89, 50))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 89, 18))
|
||||
>letter : Symbol(letter, Decl(correlatedUnions.ts, 89, 60))
|
||||
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
|
||||
>P : Symbol(P, Decl(correlatedUnions.ts, 89, 50))
|
||||
>LetterMap : Symbol(LetterMap, Decl(correlatedUnions.ts, 84, 40))
|
||||
>P : Symbol(P, Decl(correlatedUnions.ts, 89, 50))
|
||||
>caller : Symbol(caller, Decl(correlatedUnions.ts, 89, 93))
|
||||
>x : Symbol(x, Decl(correlatedUnions.ts, 89, 103))
|
||||
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
|
||||
>P : Symbol(P, Decl(correlatedUnions.ts, 89, 50))
|
||||
>LetterMap : Symbol(LetterMap, Decl(correlatedUnions.ts, 84, 40))
|
||||
>P : Symbol(P, Decl(correlatedUnions.ts, 89, 50))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 89, 18))
|
||||
|
||||
function call<K extends keyof LetterMap>({ letter, caller }: LetterCaller<K>): void {
|
||||
>call : Symbol(call, Decl(correlatedUnions.ts, 89, 146))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 91, 14))
|
||||
>LetterMap : Symbol(LetterMap, Decl(correlatedUnions.ts, 84, 40))
|
||||
>letter : Symbol(letter, Decl(correlatedUnions.ts, 91, 42))
|
||||
>caller : Symbol(caller, Decl(correlatedUnions.ts, 91, 50))
|
||||
>LetterCaller : Symbol(LetterCaller, Decl(correlatedUnions.ts, 88, 41))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 91, 14))
|
||||
|
||||
caller(letter);
|
||||
>caller : Symbol(caller, Decl(correlatedUnions.ts, 91, 50))
|
||||
>letter : Symbol(letter, Decl(correlatedUnions.ts, 91, 42))
|
||||
}
|
||||
|
||||
type A = { A: string };
|
||||
>A : Symbol(A, Decl(correlatedUnions.ts, 93, 1))
|
||||
>A : Symbol(A, Decl(correlatedUnions.ts, 95, 10))
|
||||
|
||||
type B = { B: number };
|
||||
>B : Symbol(B, Decl(correlatedUnions.ts, 95, 23))
|
||||
>B : Symbol(B, Decl(correlatedUnions.ts, 96, 10))
|
||||
|
||||
type ACaller = (a: A) => void;
|
||||
>ACaller : Symbol(ACaller, Decl(correlatedUnions.ts, 96, 23))
|
||||
>a : Symbol(a, Decl(correlatedUnions.ts, 97, 16))
|
||||
>A : Symbol(A, Decl(correlatedUnions.ts, 93, 1))
|
||||
|
||||
type BCaller = (b: B) => void;
|
||||
>BCaller : Symbol(BCaller, Decl(correlatedUnions.ts, 97, 30))
|
||||
>b : Symbol(b, Decl(correlatedUnions.ts, 98, 16))
|
||||
>B : Symbol(B, Decl(correlatedUnions.ts, 95, 23))
|
||||
|
||||
declare const xx: { letter: A, caller: ACaller } | { letter: B, caller: BCaller };
|
||||
>xx : Symbol(xx, Decl(correlatedUnions.ts, 100, 13))
|
||||
>letter : Symbol(letter, Decl(correlatedUnions.ts, 100, 19))
|
||||
>A : Symbol(A, Decl(correlatedUnions.ts, 93, 1))
|
||||
>caller : Symbol(caller, Decl(correlatedUnions.ts, 100, 30))
|
||||
>ACaller : Symbol(ACaller, Decl(correlatedUnions.ts, 96, 23))
|
||||
>letter : Symbol(letter, Decl(correlatedUnions.ts, 100, 52))
|
||||
>B : Symbol(B, Decl(correlatedUnions.ts, 95, 23))
|
||||
>caller : Symbol(caller, Decl(correlatedUnions.ts, 100, 63))
|
||||
>BCaller : Symbol(BCaller, Decl(correlatedUnions.ts, 97, 30))
|
||||
|
||||
call(xx);
|
||||
>call : Symbol(call, Decl(correlatedUnions.ts, 89, 146))
|
||||
>xx : Symbol(xx, Decl(correlatedUnions.ts, 100, 13))
|
||||
|
||||
// --------
|
||||
|
||||
type Ev<K extends keyof DocumentEventMap> = { [P in K]: {
|
||||
>Ev : Symbol(Ev, Decl(correlatedUnions.ts, 102, 9))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 106, 8))
|
||||
>DocumentEventMap : Symbol(DocumentEventMap, Decl(lib.dom.d.ts, --, --))
|
||||
>P : Symbol(P, Decl(correlatedUnions.ts, 106, 47))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 106, 8))
|
||||
|
||||
readonly name: P;
|
||||
>name : Symbol(name, Decl(correlatedUnions.ts, 106, 57))
|
||||
>P : Symbol(P, Decl(correlatedUnions.ts, 106, 47))
|
||||
|
||||
readonly once?: boolean;
|
||||
>once : Symbol(once, Decl(correlatedUnions.ts, 107, 21))
|
||||
|
||||
readonly callback: (ev: DocumentEventMap[P]) => void;
|
||||
>callback : Symbol(callback, Decl(correlatedUnions.ts, 108, 28))
|
||||
>ev : Symbol(ev, Decl(correlatedUnions.ts, 109, 24))
|
||||
>DocumentEventMap : Symbol(DocumentEventMap, Decl(lib.dom.d.ts, --, --))
|
||||
>P : Symbol(P, Decl(correlatedUnions.ts, 106, 47))
|
||||
|
||||
}}[K];
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 106, 8))
|
||||
|
||||
function processEvents<K extends keyof DocumentEventMap>(events: Ev<K>[]) {
|
||||
>processEvents : Symbol(processEvents, Decl(correlatedUnions.ts, 110, 6))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 112, 23))
|
||||
>DocumentEventMap : Symbol(DocumentEventMap, Decl(lib.dom.d.ts, --, --))
|
||||
>events : Symbol(events, Decl(correlatedUnions.ts, 112, 57))
|
||||
>Ev : Symbol(Ev, Decl(correlatedUnions.ts, 102, 9))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 112, 23))
|
||||
|
||||
for (const event of events) {
|
||||
>event : Symbol(event, Decl(correlatedUnions.ts, 113, 14))
|
||||
>events : Symbol(events, Decl(correlatedUnions.ts, 112, 57))
|
||||
|
||||
document.addEventListener(event.name, (ev) => event.callback(ev), { once: event.once });
|
||||
>document.addEventListener : Symbol(Document.addEventListener, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --))
|
||||
>document : Symbol(document, Decl(lib.dom.d.ts, --, --))
|
||||
>addEventListener : Symbol(Document.addEventListener, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --))
|
||||
>event.name : Symbol(name, Decl(correlatedUnions.ts, 106, 57))
|
||||
>event : Symbol(event, Decl(correlatedUnions.ts, 113, 14))
|
||||
>name : Symbol(name, Decl(correlatedUnions.ts, 106, 57))
|
||||
>ev : Symbol(ev, Decl(correlatedUnions.ts, 114, 47))
|
||||
>event.callback : Symbol(callback, Decl(correlatedUnions.ts, 108, 28))
|
||||
>event : Symbol(event, Decl(correlatedUnions.ts, 113, 14))
|
||||
>callback : Symbol(callback, Decl(correlatedUnions.ts, 108, 28))
|
||||
>ev : Symbol(ev, Decl(correlatedUnions.ts, 114, 47))
|
||||
>once : Symbol(once, Decl(correlatedUnions.ts, 114, 75))
|
||||
>event.once : Symbol(once, Decl(correlatedUnions.ts, 107, 21))
|
||||
>event : Symbol(event, Decl(correlatedUnions.ts, 113, 14))
|
||||
>once : Symbol(once, Decl(correlatedUnions.ts, 107, 21))
|
||||
}
|
||||
}
|
||||
|
||||
function createEventListener<K extends keyof DocumentEventMap>({ name, once = false, callback }: Ev<K>): Ev<K> {
|
||||
>createEventListener : Symbol(createEventListener, Decl(correlatedUnions.ts, 116, 1))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 118, 29))
|
||||
>DocumentEventMap : Symbol(DocumentEventMap, Decl(lib.dom.d.ts, --, --))
|
||||
>name : Symbol(name, Decl(correlatedUnions.ts, 118, 64))
|
||||
>once : Symbol(once, Decl(correlatedUnions.ts, 118, 70))
|
||||
>callback : Symbol(callback, Decl(correlatedUnions.ts, 118, 84))
|
||||
>Ev : Symbol(Ev, Decl(correlatedUnions.ts, 102, 9))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 118, 29))
|
||||
>Ev : Symbol(Ev, Decl(correlatedUnions.ts, 102, 9))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 118, 29))
|
||||
|
||||
return { name, once, callback };
|
||||
>name : Symbol(name, Decl(correlatedUnions.ts, 119, 12))
|
||||
>once : Symbol(once, Decl(correlatedUnions.ts, 119, 18))
|
||||
>callback : Symbol(callback, Decl(correlatedUnions.ts, 119, 24))
|
||||
}
|
||||
|
||||
const clickEvent = createEventListener({
|
||||
>clickEvent : Symbol(clickEvent, Decl(correlatedUnions.ts, 122, 5))
|
||||
>createEventListener : Symbol(createEventListener, Decl(correlatedUnions.ts, 116, 1))
|
||||
|
||||
name: "click",
|
||||
>name : Symbol(name, Decl(correlatedUnions.ts, 122, 40))
|
||||
|
||||
callback: ev => console.log(ev),
|
||||
>callback : Symbol(callback, Decl(correlatedUnions.ts, 123, 18))
|
||||
>ev : Symbol(ev, Decl(correlatedUnions.ts, 124, 13))
|
||||
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
|
||||
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
>ev : Symbol(ev, Decl(correlatedUnions.ts, 124, 13))
|
||||
|
||||
});
|
||||
|
||||
const scrollEvent = createEventListener({
|
||||
>scrollEvent : Symbol(scrollEvent, Decl(correlatedUnions.ts, 127, 5))
|
||||
>createEventListener : Symbol(createEventListener, Decl(correlatedUnions.ts, 116, 1))
|
||||
|
||||
name: "scroll",
|
||||
>name : Symbol(name, Decl(correlatedUnions.ts, 127, 41))
|
||||
|
||||
callback: ev => console.log(ev),
|
||||
>callback : Symbol(callback, Decl(correlatedUnions.ts, 128, 19))
|
||||
>ev : Symbol(ev, Decl(correlatedUnions.ts, 129, 13))
|
||||
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
|
||||
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
>ev : Symbol(ev, Decl(correlatedUnions.ts, 129, 13))
|
||||
|
||||
});
|
||||
|
||||
processEvents([clickEvent, scrollEvent]);
|
||||
>processEvents : Symbol(processEvents, Decl(correlatedUnions.ts, 110, 6))
|
||||
>clickEvent : Symbol(clickEvent, Decl(correlatedUnions.ts, 122, 5))
|
||||
>scrollEvent : Symbol(scrollEvent, Decl(correlatedUnions.ts, 127, 5))
|
||||
|
||||
processEvents([
|
||||
>processEvents : Symbol(processEvents, Decl(correlatedUnions.ts, 110, 6))
|
||||
|
||||
{ name: "click", callback: ev => console.log(ev) },
|
||||
>name : Symbol(name, Decl(correlatedUnions.ts, 135, 5))
|
||||
>callback : Symbol(callback, Decl(correlatedUnions.ts, 135, 20))
|
||||
>ev : Symbol(ev, Decl(correlatedUnions.ts, 135, 30))
|
||||
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
|
||||
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
>ev : Symbol(ev, Decl(correlatedUnions.ts, 135, 30))
|
||||
|
||||
{ name: "scroll", callback: ev => console.log(ev) },
|
||||
>name : Symbol(name, Decl(correlatedUnions.ts, 136, 5))
|
||||
>callback : Symbol(callback, Decl(correlatedUnions.ts, 136, 21))
|
||||
>ev : Symbol(ev, Decl(correlatedUnions.ts, 136, 31))
|
||||
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
|
||||
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
>ev : Symbol(ev, Decl(correlatedUnions.ts, 136, 31))
|
||||
|
||||
]);
|
||||
|
||||
// --------
|
||||
|
||||
function ff1() {
|
||||
>ff1 : Symbol(ff1, Decl(correlatedUnions.ts, 137, 3))
|
||||
|
||||
type ArgMap = {
|
||||
>ArgMap : Symbol(ArgMap, Decl(correlatedUnions.ts, 141, 16))
|
||||
|
||||
sum: [a: number, b: number],
|
||||
>sum : Symbol(sum, Decl(correlatedUnions.ts, 142, 19))
|
||||
|
||||
concat: [a: string, b: string, c: string]
|
||||
>concat : Symbol(concat, Decl(correlatedUnions.ts, 143, 36))
|
||||
}
|
||||
type Keys = keyof ArgMap;
|
||||
>Keys : Symbol(Keys, Decl(correlatedUnions.ts, 145, 5))
|
||||
>ArgMap : Symbol(ArgMap, Decl(correlatedUnions.ts, 141, 16))
|
||||
|
||||
const funs: { [P in Keys]: (...args: ArgMap[P]) => void } = {
|
||||
>funs : Symbol(funs, Decl(correlatedUnions.ts, 147, 9))
|
||||
>P : Symbol(P, Decl(correlatedUnions.ts, 147, 19))
|
||||
>Keys : Symbol(Keys, Decl(correlatedUnions.ts, 145, 5))
|
||||
>args : Symbol(args, Decl(correlatedUnions.ts, 147, 32))
|
||||
>ArgMap : Symbol(ArgMap, Decl(correlatedUnions.ts, 141, 16))
|
||||
>P : Symbol(P, Decl(correlatedUnions.ts, 147, 19))
|
||||
|
||||
sum: (a, b) => a + b,
|
||||
>sum : Symbol(sum, Decl(correlatedUnions.ts, 147, 65))
|
||||
>a : Symbol(a, Decl(correlatedUnions.ts, 148, 14))
|
||||
>b : Symbol(b, Decl(correlatedUnions.ts, 148, 16))
|
||||
>a : Symbol(a, Decl(correlatedUnions.ts, 148, 14))
|
||||
>b : Symbol(b, Decl(correlatedUnions.ts, 148, 16))
|
||||
|
||||
concat: (a, b, c) => a + b + c
|
||||
>concat : Symbol(concat, Decl(correlatedUnions.ts, 148, 29))
|
||||
>a : Symbol(a, Decl(correlatedUnions.ts, 149, 17))
|
||||
>b : Symbol(b, Decl(correlatedUnions.ts, 149, 19))
|
||||
>c : Symbol(c, Decl(correlatedUnions.ts, 149, 22))
|
||||
>a : Symbol(a, Decl(correlatedUnions.ts, 149, 17))
|
||||
>b : Symbol(b, Decl(correlatedUnions.ts, 149, 19))
|
||||
>c : Symbol(c, Decl(correlatedUnions.ts, 149, 22))
|
||||
}
|
||||
function apply<K extends Keys>(funKey: K, ...args: ArgMap[K]) {
|
||||
>apply : Symbol(apply, Decl(correlatedUnions.ts, 150, 5))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 151, 19))
|
||||
>Keys : Symbol(Keys, Decl(correlatedUnions.ts, 145, 5))
|
||||
>funKey : Symbol(funKey, Decl(correlatedUnions.ts, 151, 35))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 151, 19))
|
||||
>args : Symbol(args, Decl(correlatedUnions.ts, 151, 45))
|
||||
>ArgMap : Symbol(ArgMap, Decl(correlatedUnions.ts, 141, 16))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 151, 19))
|
||||
|
||||
const fn = funs[funKey];
|
||||
>fn : Symbol(fn, Decl(correlatedUnions.ts, 152, 13))
|
||||
>funs : Symbol(funs, Decl(correlatedUnions.ts, 147, 9))
|
||||
>funKey : Symbol(funKey, Decl(correlatedUnions.ts, 151, 35))
|
||||
|
||||
fn(...args);
|
||||
>fn : Symbol(fn, Decl(correlatedUnions.ts, 152, 13))
|
||||
>args : Symbol(args, Decl(correlatedUnions.ts, 151, 45))
|
||||
}
|
||||
const x1 = apply('sum', 1, 2)
|
||||
>x1 : Symbol(x1, Decl(correlatedUnions.ts, 155, 9))
|
||||
>apply : Symbol(apply, Decl(correlatedUnions.ts, 150, 5))
|
||||
|
||||
const x2 = apply('concat', 'str1', 'str2', 'str3' )
|
||||
>x2 : Symbol(x2, Decl(correlatedUnions.ts, 156, 9))
|
||||
>apply : Symbol(apply, Decl(correlatedUnions.ts, 150, 5))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,551 @@
|
||||
=== tests/cases/compiler/correlatedUnions.ts ===
|
||||
// Various repros from #30581
|
||||
|
||||
type RecordMap = { n: number, s: string, b: boolean };
|
||||
>RecordMap : RecordMap
|
||||
>n : number
|
||||
>s : string
|
||||
>b : boolean
|
||||
|
||||
type UnionRecord<K extends keyof RecordMap = keyof RecordMap> = { [P in K]: {
|
||||
>UnionRecord : UnionRecord<K>
|
||||
|
||||
kind: P,
|
||||
>kind : P
|
||||
|
||||
v: RecordMap[P],
|
||||
>v : RecordMap[P]
|
||||
|
||||
f: (v: RecordMap[P]) => void
|
||||
>f : (v: RecordMap[P]) => void
|
||||
>v : RecordMap[P]
|
||||
|
||||
}}[K];
|
||||
|
||||
function processRecord<K extends keyof RecordMap>(rec: UnionRecord<K>) {
|
||||
>processRecord : <K extends keyof RecordMap>(rec: UnionRecord<K>) => void
|
||||
>rec : UnionRecord<K>
|
||||
|
||||
rec.f(rec.v);
|
||||
>rec.f(rec.v) : void
|
||||
>rec.f : (v: RecordMap[K]) => void
|
||||
>rec : UnionRecord<K>
|
||||
>f : (v: RecordMap[K]) => void
|
||||
>rec.v : RecordMap[K]
|
||||
>rec : UnionRecord<K>
|
||||
>v : RecordMap[K]
|
||||
}
|
||||
|
||||
declare const r1: UnionRecord<'n'>; // { kind: 'n', v: number, f: (v: number) => void }
|
||||
>r1 : { kind: "n"; v: number; f: (v: number) => void; }
|
||||
|
||||
declare const r2: UnionRecord; // { kind: 'n', ... } | { kind: 's', ... } | { kind: 'b', ... }
|
||||
>r2 : UnionRecord<keyof RecordMap>
|
||||
|
||||
processRecord(r1);
|
||||
>processRecord(r1) : void
|
||||
>processRecord : <K extends keyof RecordMap>(rec: UnionRecord<K>) => void
|
||||
>r1 : { kind: "n"; v: number; f: (v: number) => void; }
|
||||
|
||||
processRecord(r2);
|
||||
>processRecord(r2) : void
|
||||
>processRecord : <K extends keyof RecordMap>(rec: UnionRecord<K>) => void
|
||||
>r2 : UnionRecord<keyof RecordMap>
|
||||
|
||||
processRecord({ kind: 'n', v: 42, f: v => v.toExponential() });
|
||||
>processRecord({ kind: 'n', v: 42, f: v => v.toExponential() }) : void
|
||||
>processRecord : <K extends keyof RecordMap>(rec: UnionRecord<K>) => void
|
||||
>{ kind: 'n', v: 42, f: v => v.toExponential() } : { kind: "n"; v: number; f: (v: number) => string; }
|
||||
>kind : "n"
|
||||
>'n' : "n"
|
||||
>v : number
|
||||
>42 : 42
|
||||
>f : (v: number) => string
|
||||
>v => v.toExponential() : (v: number) => string
|
||||
>v : number
|
||||
>v.toExponential() : string
|
||||
>v.toExponential : (fractionDigits?: number | undefined) => string
|
||||
>v : number
|
||||
>toExponential : (fractionDigits?: number | undefined) => string
|
||||
|
||||
// --------
|
||||
|
||||
type TextFieldData = { value: string }
|
||||
>TextFieldData : TextFieldData
|
||||
>value : string
|
||||
|
||||
type SelectFieldData = { options: string[], selectedValue: string }
|
||||
>SelectFieldData : SelectFieldData
|
||||
>options : string[]
|
||||
>selectedValue : string
|
||||
|
||||
type FieldMap = {
|
||||
>FieldMap : FieldMap
|
||||
|
||||
text: TextFieldData;
|
||||
>text : TextFieldData
|
||||
|
||||
select: SelectFieldData;
|
||||
>select : SelectFieldData
|
||||
}
|
||||
|
||||
type FormField<K extends keyof FieldMap> = { type: K, data: FieldMap[K] };
|
||||
>FormField : FormField<K>
|
||||
>type : K
|
||||
>data : FieldMap[K]
|
||||
|
||||
type RenderFunc<K extends keyof FieldMap> = (props: FieldMap[K]) => void;
|
||||
>RenderFunc : RenderFunc<K>
|
||||
>props : FieldMap[K]
|
||||
|
||||
type RenderFuncMap = { [K in keyof FieldMap]: RenderFunc<K> };
|
||||
>RenderFuncMap : RenderFuncMap
|
||||
|
||||
function renderTextField(props: TextFieldData) {}
|
||||
>renderTextField : (props: TextFieldData) => void
|
||||
>props : TextFieldData
|
||||
|
||||
function renderSelectField(props: SelectFieldData) {}
|
||||
>renderSelectField : (props: SelectFieldData) => void
|
||||
>props : SelectFieldData
|
||||
|
||||
const renderFuncs: RenderFuncMap = {
|
||||
>renderFuncs : RenderFuncMap
|
||||
>{ text: renderTextField, select: renderSelectField,} : { text: (props: TextFieldData) => void; select: (props: SelectFieldData) => void; }
|
||||
|
||||
text: renderTextField,
|
||||
>text : (props: TextFieldData) => void
|
||||
>renderTextField : (props: TextFieldData) => void
|
||||
|
||||
select: renderSelectField,
|
||||
>select : (props: SelectFieldData) => void
|
||||
>renderSelectField : (props: SelectFieldData) => void
|
||||
|
||||
};
|
||||
|
||||
function renderField<K extends keyof FieldMap>(field: FormField<K>) {
|
||||
>renderField : <K extends keyof FieldMap>(field: FormField<K>) => void
|
||||
>field : FormField<K>
|
||||
|
||||
const renderFn = renderFuncs[field.type];
|
||||
>renderFn : RenderFuncMap[K]
|
||||
>renderFuncs[field.type] : RenderFuncMap[K]
|
||||
>renderFuncs : RenderFuncMap
|
||||
>field.type : K
|
||||
>field : FormField<K>
|
||||
>type : K
|
||||
|
||||
renderFn(field.data);
|
||||
>renderFn(field.data) : void
|
||||
>renderFn : RenderFuncMap[K]
|
||||
>field.data : FieldMap[K]
|
||||
>field : FormField<K>
|
||||
>data : FieldMap[K]
|
||||
}
|
||||
|
||||
// --------
|
||||
|
||||
type TypeMap = {
|
||||
>TypeMap : TypeMap
|
||||
|
||||
foo: string,
|
||||
>foo : string
|
||||
|
||||
bar: number
|
||||
>bar : number
|
||||
|
||||
};
|
||||
|
||||
type Keys = keyof TypeMap;
|
||||
>Keys : keyof TypeMap
|
||||
|
||||
type HandlerMap = { [P in Keys]: (x: TypeMap[P]) => void };
|
||||
>HandlerMap : HandlerMap
|
||||
>x : TypeMap[P]
|
||||
|
||||
const handlers: HandlerMap = {
|
||||
>handlers : HandlerMap
|
||||
>{ foo: s => s.length, bar: n => n.toFixed(2)} : { foo: (s: string) => number; bar: (n: number) => string; }
|
||||
|
||||
foo: s => s.length,
|
||||
>foo : (s: string) => number
|
||||
>s => s.length : (s: string) => number
|
||||
>s : string
|
||||
>s.length : number
|
||||
>s : string
|
||||
>length : number
|
||||
|
||||
bar: n => n.toFixed(2)
|
||||
>bar : (n: number) => string
|
||||
>n => n.toFixed(2) : (n: number) => string
|
||||
>n : number
|
||||
>n.toFixed(2) : string
|
||||
>n.toFixed : (fractionDigits?: number | undefined) => string
|
||||
>n : number
|
||||
>toFixed : (fractionDigits?: number | undefined) => string
|
||||
>2 : 2
|
||||
|
||||
};
|
||||
|
||||
type DataEntry<K extends Keys = Keys> = { [P in K]: {
|
||||
>DataEntry : DataEntry<K>
|
||||
|
||||
type: P,
|
||||
>type : P
|
||||
|
||||
data: TypeMap[P]
|
||||
>data : TypeMap[P]
|
||||
|
||||
}}[K];
|
||||
|
||||
const data: DataEntry[] = [
|
||||
>data : DataEntry<keyof TypeMap>[]
|
||||
>[ { type: 'foo', data: 'abc' }, { type: 'foo', data: 'def' }, { type: 'bar', data: 42 },] : ({ type: "foo"; data: string; } | { type: "bar"; data: number; })[]
|
||||
|
||||
{ type: 'foo', data: 'abc' },
|
||||
>{ type: 'foo', data: 'abc' } : { type: "foo"; data: string; }
|
||||
>type : "foo"
|
||||
>'foo' : "foo"
|
||||
>data : string
|
||||
>'abc' : "abc"
|
||||
|
||||
{ type: 'foo', data: 'def' },
|
||||
>{ type: 'foo', data: 'def' } : { type: "foo"; data: string; }
|
||||
>type : "foo"
|
||||
>'foo' : "foo"
|
||||
>data : string
|
||||
>'def' : "def"
|
||||
|
||||
{ type: 'bar', data: 42 },
|
||||
>{ type: 'bar', data: 42 } : { type: "bar"; data: number; }
|
||||
>type : "bar"
|
||||
>'bar' : "bar"
|
||||
>data : number
|
||||
>42 : 42
|
||||
|
||||
];
|
||||
|
||||
function process<K extends Keys>(data: DataEntry<K>[]) {
|
||||
>process : <K extends keyof TypeMap>(data: DataEntry<K>[]) => void
|
||||
>data : DataEntry<K>[]
|
||||
|
||||
data.forEach(block => {
|
||||
>data.forEach(block => { if (block.type in handlers) { handlers[block.type](block.data) } }) : void
|
||||
>data.forEach : (callbackfn: (value: DataEntry<K>, index: number, array: DataEntry<K>[]) => void, thisArg?: any) => void
|
||||
>data : DataEntry<K>[]
|
||||
>forEach : (callbackfn: (value: DataEntry<K>, index: number, array: DataEntry<K>[]) => void, thisArg?: any) => void
|
||||
>block => { if (block.type in handlers) { handlers[block.type](block.data) } } : (block: DataEntry<K>) => void
|
||||
>block : DataEntry<K>
|
||||
|
||||
if (block.type in handlers) {
|
||||
>block.type in handlers : boolean
|
||||
>block.type : K
|
||||
>block : DataEntry<K>
|
||||
>type : K
|
||||
>handlers : HandlerMap
|
||||
|
||||
handlers[block.type](block.data)
|
||||
>handlers[block.type](block.data) : void
|
||||
>handlers[block.type] : HandlerMap[K]
|
||||
>handlers : HandlerMap
|
||||
>block.type : K
|
||||
>block : DataEntry<K>
|
||||
>type : K
|
||||
>block.data : TypeMap[K]
|
||||
>block : DataEntry<K>
|
||||
>data : TypeMap[K]
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
process(data);
|
||||
>process(data) : void
|
||||
>process : <K extends keyof TypeMap>(data: DataEntry<K>[]) => void
|
||||
>data : DataEntry<keyof TypeMap>[]
|
||||
|
||||
process([{ type: 'foo', data: 'abc' }]);
|
||||
>process([{ type: 'foo', data: 'abc' }]) : void
|
||||
>process : <K extends keyof TypeMap>(data: DataEntry<K>[]) => void
|
||||
>[{ type: 'foo', data: 'abc' }] : { type: "foo"; data: string; }[]
|
||||
>{ type: 'foo', data: 'abc' } : { type: "foo"; data: string; }
|
||||
>type : "foo"
|
||||
>'foo' : "foo"
|
||||
>data : string
|
||||
>'abc' : "abc"
|
||||
|
||||
// --------
|
||||
|
||||
type LetterMap = { A: string, B: number }
|
||||
>LetterMap : LetterMap
|
||||
>A : string
|
||||
>B : number
|
||||
|
||||
type LetterCaller<K extends keyof LetterMap> = { [P in K]: { letter: Record<P, LetterMap[P]>, caller: (x: Record<P, LetterMap[P]>) => void } }[K];
|
||||
>LetterCaller : LetterCaller<K>
|
||||
>letter : Record<P, LetterMap[P]>
|
||||
>caller : (x: Record<P, LetterMap[P]>) => void
|
||||
>x : Record<P, LetterMap[P]>
|
||||
|
||||
function call<K extends keyof LetterMap>({ letter, caller }: LetterCaller<K>): void {
|
||||
>call : <K extends keyof LetterMap>({ letter, caller }: LetterCaller<K>) => void
|
||||
>letter : Record<K, LetterMap[K]>
|
||||
>caller : (x: Record<K, LetterMap[K]>) => void
|
||||
|
||||
caller(letter);
|
||||
>caller(letter) : void
|
||||
>caller : (x: Record<K, LetterMap[K]>) => void
|
||||
>letter : Record<K, LetterMap[K]>
|
||||
}
|
||||
|
||||
type A = { A: string };
|
||||
>A : A
|
||||
>A : string
|
||||
|
||||
type B = { B: number };
|
||||
>B : B
|
||||
>B : number
|
||||
|
||||
type ACaller = (a: A) => void;
|
||||
>ACaller : ACaller
|
||||
>a : A
|
||||
|
||||
type BCaller = (b: B) => void;
|
||||
>BCaller : BCaller
|
||||
>b : B
|
||||
|
||||
declare const xx: { letter: A, caller: ACaller } | { letter: B, caller: BCaller };
|
||||
>xx : { letter: A; caller: ACaller; } | { letter: B; caller: BCaller; }
|
||||
>letter : A
|
||||
>caller : ACaller
|
||||
>letter : B
|
||||
>caller : BCaller
|
||||
|
||||
call(xx);
|
||||
>call(xx) : void
|
||||
>call : <K extends keyof LetterMap>({ letter, caller }: LetterCaller<K>) => void
|
||||
>xx : { letter: A; caller: ACaller; } | { letter: B; caller: BCaller; }
|
||||
|
||||
// --------
|
||||
|
||||
type Ev<K extends keyof DocumentEventMap> = { [P in K]: {
|
||||
>Ev : Ev<K>
|
||||
|
||||
readonly name: P;
|
||||
>name : P
|
||||
|
||||
readonly once?: boolean;
|
||||
>once : boolean | undefined
|
||||
|
||||
readonly callback: (ev: DocumentEventMap[P]) => void;
|
||||
>callback : (ev: DocumentEventMap[P]) => void
|
||||
>ev : DocumentEventMap[P]
|
||||
|
||||
}}[K];
|
||||
|
||||
function processEvents<K extends keyof DocumentEventMap>(events: Ev<K>[]) {
|
||||
>processEvents : <K extends keyof DocumentEventMap>(events: Ev<K>[]) => void
|
||||
>events : Ev<K>[]
|
||||
|
||||
for (const event of events) {
|
||||
>event : Ev<K>
|
||||
>events : Ev<K>[]
|
||||
|
||||
document.addEventListener(event.name, (ev) => event.callback(ev), { once: event.once });
|
||||
>document.addEventListener(event.name, (ev) => event.callback(ev), { once: event.once }) : void
|
||||
>document.addEventListener : { <K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions | undefined): void; (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions | undefined): void; }
|
||||
>document : Document
|
||||
>addEventListener : { <K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions | undefined): void; (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions | undefined): void; }
|
||||
>event.name : K
|
||||
>event : Ev<K>
|
||||
>name : K
|
||||
>(ev) => event.callback(ev) : (this: Document, ev: DocumentEventMap[K]) => void
|
||||
>ev : DocumentEventMap[K]
|
||||
>event.callback(ev) : void
|
||||
>event.callback : (ev: DocumentEventMap[K]) => void
|
||||
>event : Ev<K>
|
||||
>callback : (ev: DocumentEventMap[K]) => void
|
||||
>ev : DocumentEventMap[K]
|
||||
>{ once: event.once } : { once: boolean | undefined; }
|
||||
>once : boolean | undefined
|
||||
>event.once : boolean | undefined
|
||||
>event : Ev<K>
|
||||
>once : boolean | undefined
|
||||
}
|
||||
}
|
||||
|
||||
function createEventListener<K extends keyof DocumentEventMap>({ name, once = false, callback }: Ev<K>): Ev<K> {
|
||||
>createEventListener : <K extends keyof DocumentEventMap>({ name, once, callback }: Ev<K>) => Ev<K>
|
||||
>name : K
|
||||
>once : boolean
|
||||
>false : false
|
||||
>callback : (ev: DocumentEventMap[K]) => void
|
||||
|
||||
return { name, once, callback };
|
||||
>{ name, once, callback } : { name: K; once: boolean; callback: (ev: DocumentEventMap[K]) => void; }
|
||||
>name : K
|
||||
>once : boolean
|
||||
>callback : (ev: DocumentEventMap[K]) => void
|
||||
}
|
||||
|
||||
const clickEvent = createEventListener({
|
||||
>clickEvent : { readonly name: "click"; readonly once?: boolean | undefined; readonly callback: (ev: MouseEvent) => void; }
|
||||
>createEventListener({ name: "click", callback: ev => console.log(ev),}) : { readonly name: "click"; readonly once?: boolean | undefined; readonly callback: (ev: MouseEvent) => void; }
|
||||
>createEventListener : <K extends keyof DocumentEventMap>({ name, once, callback }: Ev<K>) => Ev<K>
|
||||
>{ name: "click", callback: ev => console.log(ev),} : { name: "click"; callback: (ev: MouseEvent) => void; }
|
||||
|
||||
name: "click",
|
||||
>name : "click"
|
||||
>"click" : "click"
|
||||
|
||||
callback: ev => console.log(ev),
|
||||
>callback : (ev: MouseEvent) => void
|
||||
>ev => console.log(ev) : (ev: MouseEvent) => void
|
||||
>ev : MouseEvent
|
||||
>console.log(ev) : void
|
||||
>console.log : (...data: any[]) => void
|
||||
>console : Console
|
||||
>log : (...data: any[]) => void
|
||||
>ev : MouseEvent
|
||||
|
||||
});
|
||||
|
||||
const scrollEvent = createEventListener({
|
||||
>scrollEvent : { readonly name: "scroll"; readonly once?: boolean | undefined; readonly callback: (ev: Event) => void; }
|
||||
>createEventListener({ name: "scroll", callback: ev => console.log(ev),}) : { readonly name: "scroll"; readonly once?: boolean | undefined; readonly callback: (ev: Event) => void; }
|
||||
>createEventListener : <K extends keyof DocumentEventMap>({ name, once, callback }: Ev<K>) => Ev<K>
|
||||
>{ name: "scroll", callback: ev => console.log(ev),} : { name: "scroll"; callback: (ev: Event) => void; }
|
||||
|
||||
name: "scroll",
|
||||
>name : "scroll"
|
||||
>"scroll" : "scroll"
|
||||
|
||||
callback: ev => console.log(ev),
|
||||
>callback : (ev: Event) => void
|
||||
>ev => console.log(ev) : (ev: Event) => void
|
||||
>ev : Event
|
||||
>console.log(ev) : void
|
||||
>console.log : (...data: any[]) => void
|
||||
>console : Console
|
||||
>log : (...data: any[]) => void
|
||||
>ev : Event
|
||||
|
||||
});
|
||||
|
||||
processEvents([clickEvent, scrollEvent]);
|
||||
>processEvents([clickEvent, scrollEvent]) : void
|
||||
>processEvents : <K extends keyof DocumentEventMap>(events: Ev<K>[]) => void
|
||||
>[clickEvent, scrollEvent] : ({ readonly name: "click"; readonly once?: boolean | undefined; readonly callback: (ev: MouseEvent) => void; } | { readonly name: "scroll"; readonly once?: boolean | undefined; readonly callback: (ev: Event) => void; })[]
|
||||
>clickEvent : { readonly name: "click"; readonly once?: boolean | undefined; readonly callback: (ev: MouseEvent) => void; }
|
||||
>scrollEvent : { readonly name: "scroll"; readonly once?: boolean | undefined; readonly callback: (ev: Event) => void; }
|
||||
|
||||
processEvents([
|
||||
>processEvents([ { name: "click", callback: ev => console.log(ev) }, { name: "scroll", callback: ev => console.log(ev) },]) : void
|
||||
>processEvents : <K extends keyof DocumentEventMap>(events: Ev<K>[]) => void
|
||||
>[ { name: "click", callback: ev => console.log(ev) }, { name: "scroll", callback: ev => console.log(ev) },] : ({ name: "click"; callback: (ev: MouseEvent) => void; } | { name: "scroll"; callback: (ev: Event) => void; })[]
|
||||
|
||||
{ name: "click", callback: ev => console.log(ev) },
|
||||
>{ name: "click", callback: ev => console.log(ev) } : { name: "click"; callback: (ev: MouseEvent) => void; }
|
||||
>name : "click"
|
||||
>"click" : "click"
|
||||
>callback : (ev: MouseEvent) => void
|
||||
>ev => console.log(ev) : (ev: MouseEvent) => void
|
||||
>ev : MouseEvent
|
||||
>console.log(ev) : void
|
||||
>console.log : (...data: any[]) => void
|
||||
>console : Console
|
||||
>log : (...data: any[]) => void
|
||||
>ev : MouseEvent
|
||||
|
||||
{ name: "scroll", callback: ev => console.log(ev) },
|
||||
>{ name: "scroll", callback: ev => console.log(ev) } : { name: "scroll"; callback: (ev: Event) => void; }
|
||||
>name : "scroll"
|
||||
>"scroll" : "scroll"
|
||||
>callback : (ev: Event) => void
|
||||
>ev => console.log(ev) : (ev: Event) => void
|
||||
>ev : Event
|
||||
>console.log(ev) : void
|
||||
>console.log : (...data: any[]) => void
|
||||
>console : Console
|
||||
>log : (...data: any[]) => void
|
||||
>ev : Event
|
||||
|
||||
]);
|
||||
|
||||
// --------
|
||||
|
||||
function ff1() {
|
||||
>ff1 : () => void
|
||||
|
||||
type ArgMap = {
|
||||
>ArgMap : { sum: [a: number, b: number]; concat: [a: string, b: string, c: string]; }
|
||||
|
||||
sum: [a: number, b: number],
|
||||
>sum : [a: number, b: number]
|
||||
|
||||
concat: [a: string, b: string, c: string]
|
||||
>concat : [a: string, b: string, c: string]
|
||||
}
|
||||
type Keys = keyof ArgMap;
|
||||
>Keys : keyof { sum: [a: number, b: number]; concat: [a: string, b: string, c: string]; }
|
||||
|
||||
const funs: { [P in Keys]: (...args: ArgMap[P]) => void } = {
|
||||
>funs : { concat: (a: string, b: string, c: string) => void; sum: (a: number, b: number) => void; }
|
||||
>args : { sum: [a: number, b: number]; concat: [a: string, b: string, c: string]; }[P]
|
||||
>{ sum: (a, b) => a + b, concat: (a, b, c) => a + b + c } : { sum: (a: number, b: number) => number; concat: (a: string, b: string, c: string) => string; }
|
||||
|
||||
sum: (a, b) => a + b,
|
||||
>sum : (a: number, b: number) => number
|
||||
>(a, b) => a + b : (a: number, b: number) => number
|
||||
>a : number
|
||||
>b : number
|
||||
>a + b : number
|
||||
>a : number
|
||||
>b : number
|
||||
|
||||
concat: (a, b, c) => a + b + c
|
||||
>concat : (a: string, b: string, c: string) => string
|
||||
>(a, b, c) => a + b + c : (a: string, b: string, c: string) => string
|
||||
>a : string
|
||||
>b : string
|
||||
>c : string
|
||||
>a + b + c : string
|
||||
>a + b : string
|
||||
>a : string
|
||||
>b : string
|
||||
>c : string
|
||||
}
|
||||
function apply<K extends Keys>(funKey: K, ...args: ArgMap[K]) {
|
||||
>apply : <K extends keyof { sum: [a: number, b: number]; concat: [a: string, b: string, c: string]; }>(funKey: K, ...args: { sum: [a: number, b: number]; concat: [a: string, b: string, c: string]; }[K]) => void
|
||||
>funKey : K
|
||||
>args : { sum: [a: number, b: number]; concat: [a: string, b: string, c: string]; }[K]
|
||||
|
||||
const fn = funs[funKey];
|
||||
>fn : { concat: (a: string, b: string, c: string) => void; sum: (a: number, b: number) => void; }[K]
|
||||
>funs[funKey] : { concat: (a: string, b: string, c: string) => void; sum: (a: number, b: number) => void; }[K]
|
||||
>funs : { concat: (a: string, b: string, c: string) => void; sum: (a: number, b: number) => void; }
|
||||
>funKey : K
|
||||
|
||||
fn(...args);
|
||||
>fn(...args) : void
|
||||
>fn : { concat: (a: string, b: string, c: string) => void; sum: (a: number, b: number) => void; }[K]
|
||||
>...args : string | number
|
||||
>args : { sum: [a: number, b: number]; concat: [a: string, b: string, c: string]; }[K]
|
||||
}
|
||||
const x1 = apply('sum', 1, 2)
|
||||
>x1 : void
|
||||
>apply('sum', 1, 2) : void
|
||||
>apply : <K extends keyof { sum: [a: number, b: number]; concat: [a: string, b: string, c: string]; }>(funKey: K, ...args: { sum: [a: number, b: number]; concat: [a: string, b: string, c: string]; }[K]) => void
|
||||
>'sum' : "sum"
|
||||
>1 : 1
|
||||
>2 : 2
|
||||
|
||||
const x2 = apply('concat', 'str1', 'str2', 'str3' )
|
||||
>x2 : void
|
||||
>apply('concat', 'str1', 'str2', 'str3' ) : void
|
||||
>apply : <K extends keyof { sum: [a: number, b: number]; concat: [a: string, b: string, c: string]; }>(funKey: K, ...args: { sum: [a: number, b: number]; concat: [a: string, b: string, c: string]; }[K]) => void
|
||||
>'concat' : "concat"
|
||||
>'str1' : "str1"
|
||||
>'str2' : "str2"
|
||||
>'str3' : "str3"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
// @strict: true
|
||||
// @declaration: true
|
||||
|
||||
// Various repros from #30581
|
||||
|
||||
type RecordMap = { n: number, s: string, b: boolean };
|
||||
type UnionRecord<K extends keyof RecordMap = keyof RecordMap> = { [P in K]: {
|
||||
kind: P,
|
||||
v: RecordMap[P],
|
||||
f: (v: RecordMap[P]) => void
|
||||
}}[K];
|
||||
|
||||
function processRecord<K extends keyof RecordMap>(rec: UnionRecord<K>) {
|
||||
rec.f(rec.v);
|
||||
}
|
||||
|
||||
declare const r1: UnionRecord<'n'>; // { kind: 'n', v: number, f: (v: number) => void }
|
||||
declare const r2: UnionRecord; // { kind: 'n', ... } | { kind: 's', ... } | { kind: 'b', ... }
|
||||
|
||||
processRecord(r1);
|
||||
processRecord(r2);
|
||||
processRecord({ kind: 'n', v: 42, f: v => v.toExponential() });
|
||||
|
||||
// --------
|
||||
|
||||
type TextFieldData = { value: string }
|
||||
type SelectFieldData = { options: string[], selectedValue: string }
|
||||
|
||||
type FieldMap = {
|
||||
text: TextFieldData;
|
||||
select: SelectFieldData;
|
||||
}
|
||||
|
||||
type FormField<K extends keyof FieldMap> = { type: K, data: FieldMap[K] };
|
||||
|
||||
type RenderFunc<K extends keyof FieldMap> = (props: FieldMap[K]) => void;
|
||||
type RenderFuncMap = { [K in keyof FieldMap]: RenderFunc<K> };
|
||||
|
||||
function renderTextField(props: TextFieldData) {}
|
||||
function renderSelectField(props: SelectFieldData) {}
|
||||
|
||||
const renderFuncs: RenderFuncMap = {
|
||||
text: renderTextField,
|
||||
select: renderSelectField,
|
||||
};
|
||||
|
||||
function renderField<K extends keyof FieldMap>(field: FormField<K>) {
|
||||
const renderFn = renderFuncs[field.type];
|
||||
renderFn(field.data);
|
||||
}
|
||||
|
||||
// --------
|
||||
|
||||
type TypeMap = {
|
||||
foo: string,
|
||||
bar: number
|
||||
};
|
||||
|
||||
type Keys = keyof TypeMap;
|
||||
|
||||
type HandlerMap = { [P in Keys]: (x: TypeMap[P]) => void };
|
||||
|
||||
const handlers: HandlerMap = {
|
||||
foo: s => s.length,
|
||||
bar: n => n.toFixed(2)
|
||||
};
|
||||
|
||||
type DataEntry<K extends Keys = Keys> = { [P in K]: {
|
||||
type: P,
|
||||
data: TypeMap[P]
|
||||
}}[K];
|
||||
|
||||
const data: DataEntry[] = [
|
||||
{ type: 'foo', data: 'abc' },
|
||||
{ type: 'foo', data: 'def' },
|
||||
{ type: 'bar', data: 42 },
|
||||
];
|
||||
|
||||
function process<K extends Keys>(data: DataEntry<K>[]) {
|
||||
data.forEach(block => {
|
||||
if (block.type in handlers) {
|
||||
handlers[block.type](block.data)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
process(data);
|
||||
process([{ type: 'foo', data: 'abc' }]);
|
||||
|
||||
// --------
|
||||
|
||||
type LetterMap = { A: string, B: number }
|
||||
type LetterCaller<K extends keyof LetterMap> = { [P in K]: { letter: Record<P, LetterMap[P]>, caller: (x: Record<P, LetterMap[P]>) => void } }[K];
|
||||
|
||||
function call<K extends keyof LetterMap>({ letter, caller }: LetterCaller<K>): void {
|
||||
caller(letter);
|
||||
}
|
||||
|
||||
type A = { A: string };
|
||||
type B = { B: number };
|
||||
type ACaller = (a: A) => void;
|
||||
type BCaller = (b: B) => void;
|
||||
|
||||
declare const xx: { letter: A, caller: ACaller } | { letter: B, caller: BCaller };
|
||||
|
||||
call(xx);
|
||||
|
||||
// --------
|
||||
|
||||
type Ev<K extends keyof DocumentEventMap> = { [P in K]: {
|
||||
readonly name: P;
|
||||
readonly once?: boolean;
|
||||
readonly callback: (ev: DocumentEventMap[P]) => void;
|
||||
}}[K];
|
||||
|
||||
function processEvents<K extends keyof DocumentEventMap>(events: Ev<K>[]) {
|
||||
for (const event of events) {
|
||||
document.addEventListener(event.name, (ev) => event.callback(ev), { once: event.once });
|
||||
}
|
||||
}
|
||||
|
||||
function createEventListener<K extends keyof DocumentEventMap>({ name, once = false, callback }: Ev<K>): Ev<K> {
|
||||
return { name, once, callback };
|
||||
}
|
||||
|
||||
const clickEvent = createEventListener({
|
||||
name: "click",
|
||||
callback: ev => console.log(ev),
|
||||
});
|
||||
|
||||
const scrollEvent = createEventListener({
|
||||
name: "scroll",
|
||||
callback: ev => console.log(ev),
|
||||
});
|
||||
|
||||
processEvents([clickEvent, scrollEvent]);
|
||||
|
||||
processEvents([
|
||||
{ name: "click", callback: ev => console.log(ev) },
|
||||
{ name: "scroll", callback: ev => console.log(ev) },
|
||||
]);
|
||||
|
||||
// --------
|
||||
|
||||
function ff1() {
|
||||
type ArgMap = {
|
||||
sum: [a: number, b: number],
|
||||
concat: [a: string, b: string, c: string]
|
||||
}
|
||||
type Keys = keyof ArgMap;
|
||||
const funs: { [P in Keys]: (...args: ArgMap[P]) => void } = {
|
||||
sum: (a, b) => a + b,
|
||||
concat: (a, b, c) => a + b + c
|
||||
}
|
||||
function apply<K extends Keys>(funKey: K, ...args: ArgMap[K]) {
|
||||
const fn = funs[funKey];
|
||||
fn(...args);
|
||||
}
|
||||
const x1 = apply('sum', 1, 2)
|
||||
const x2 = apply('concat', 'str1', 'str2', 'str3' )
|
||||
}
|
||||
Reference in New Issue
Block a user