Skip to content

Commit

Permalink
Preserve generics in contextual types for rest arguments (#44122)
Browse files Browse the repository at this point in the history
* Move all getIndexedAccessType flags to AccessFlags enum

* Preserve generics in contextual types for rest arguments

* Add regression test
  • Loading branch information
ahejlsberg committed May 19, 2021
1 parent 73736d9 commit e67da8a
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 50 deletions.
84 changes: 40 additions & 44 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

23 changes: 17 additions & 6 deletions src/compiler/types.ts
Expand Up @@ -5491,17 +5491,28 @@ namespace ts {
resolvedDefaultType?: Type;
}

/* @internal */
export const enum AccessFlags {
None = 0,
IncludeUndefined = 1 << 0,
NoIndexSignatures = 1 << 1,
Writing = 1 << 2,
CacheSymbol = 1 << 3,
NoTupleBoundsCheck = 1 << 4,
ExpressionPosition = 1 << 5,
ReportDeprecated = 1 << 6,
SuppressNoImplicitAnyError = 1 << 7,
Contextual = 1 << 8,
Persistent = IncludeUndefined,
}

// Indexed access types (TypeFlags.IndexedAccess)
// Possible forms are T[xxx], xxx[T], or xxx[keyof T], where T is a type variable
export interface IndexedAccessType extends InstantiableType {
objectType: Type;
indexType: Type;
/**
* @internal
* Indicates that --noUncheckedIndexedAccess may introduce 'undefined' into
* the resulting type, depending on how type variable constraints are resolved.
*/
noUncheckedIndexedAccessCandidate: boolean;
/* @internal */
accessFlags: AccessFlags; // Only includes AccessFlags.Persistent
constraint?: Type;
simplifiedForReading?: Type;
simplifiedForWriting?: Type;
Expand Down
10 changes: 10 additions & 0 deletions tests/baselines/reference/controlFlowGenericTypes.errors.txt
Expand Up @@ -149,4 +149,14 @@ tests/cases/conformance/controlFlow/controlFlowGenericTypes.ts(91,11): error TS2
}
return 0;
};

// Repro from #44093

class EventEmitter<ET> {
off<K extends keyof ET>(...args: [K, number] | [unknown, string]):void {}
}
function once<ET, T extends EventEmitter<ET>>(emittingObject: T, eventName: keyof ET): void {
emittingObject.off(eventName, 0);
emittingObject.off(eventName as typeof eventName, 0);
}

26 changes: 26 additions & 0 deletions tests/baselines/reference/controlFlowGenericTypes.js
Expand Up @@ -128,6 +128,16 @@ function get<K extends keyof A>(key: K, obj: A): number {
}
return 0;
};

// Repro from #44093

class EventEmitter<ET> {
off<K extends keyof ET>(...args: [K, number] | [unknown, string]):void {}
}
function once<ET, T extends EventEmitter<ET>>(emittingObject: T, eventName: keyof ET): void {
emittingObject.off(eventName, 0);
emittingObject.off(eventName as typeof eventName, 0);
}


//// [controlFlowGenericTypes.js]
Expand Down Expand Up @@ -220,3 +230,19 @@ function get(key, obj) {
return 0;
}
;
// Repro from #44093
var EventEmitter = /** @class */ (function () {
function EventEmitter() {
}
EventEmitter.prototype.off = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
};
return EventEmitter;
}());
function once(emittingObject, eventName) {
emittingObject.off(eventName, 0);
emittingObject.off(eventName, 0);
}
38 changes: 38 additions & 0 deletions tests/baselines/reference/controlFlowGenericTypes.symbols
Expand Up @@ -367,3 +367,41 @@ function get<K extends keyof A>(key: K, obj: A): number {
return 0;
};

// Repro from #44093

class EventEmitter<ET> {
>EventEmitter : Symbol(EventEmitter, Decl(controlFlowGenericTypes.ts, 128, 2))
>ET : Symbol(ET, Decl(controlFlowGenericTypes.ts, 132, 19))

off<K extends keyof ET>(...args: [K, number] | [unknown, string]):void {}
>off : Symbol(EventEmitter.off, Decl(controlFlowGenericTypes.ts, 132, 24))
>K : Symbol(K, Decl(controlFlowGenericTypes.ts, 133, 8))
>ET : Symbol(ET, Decl(controlFlowGenericTypes.ts, 132, 19))
>args : Symbol(args, Decl(controlFlowGenericTypes.ts, 133, 28))
>K : Symbol(K, Decl(controlFlowGenericTypes.ts, 133, 8))
}
function once<ET, T extends EventEmitter<ET>>(emittingObject: T, eventName: keyof ET): void {
>once : Symbol(once, Decl(controlFlowGenericTypes.ts, 134, 1))
>ET : Symbol(ET, Decl(controlFlowGenericTypes.ts, 135, 14))
>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 135, 17))
>EventEmitter : Symbol(EventEmitter, Decl(controlFlowGenericTypes.ts, 128, 2))
>ET : Symbol(ET, Decl(controlFlowGenericTypes.ts, 135, 14))
>emittingObject : Symbol(emittingObject, Decl(controlFlowGenericTypes.ts, 135, 46))
>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 135, 17))
>eventName : Symbol(eventName, Decl(controlFlowGenericTypes.ts, 135, 64))
>ET : Symbol(ET, Decl(controlFlowGenericTypes.ts, 135, 14))

emittingObject.off(eventName, 0);
>emittingObject.off : Symbol(EventEmitter.off, Decl(controlFlowGenericTypes.ts, 132, 24))
>emittingObject : Symbol(emittingObject, Decl(controlFlowGenericTypes.ts, 135, 46))
>off : Symbol(EventEmitter.off, Decl(controlFlowGenericTypes.ts, 132, 24))
>eventName : Symbol(eventName, Decl(controlFlowGenericTypes.ts, 135, 64))

emittingObject.off(eventName as typeof eventName, 0);
>emittingObject.off : Symbol(EventEmitter.off, Decl(controlFlowGenericTypes.ts, 132, 24))
>emittingObject : Symbol(emittingObject, Decl(controlFlowGenericTypes.ts, 135, 46))
>off : Symbol(EventEmitter.off, Decl(controlFlowGenericTypes.ts, 132, 24))
>eventName : Symbol(eventName, Decl(controlFlowGenericTypes.ts, 135, 64))
>eventName : Symbol(eventName, Decl(controlFlowGenericTypes.ts, 135, 64))
}

33 changes: 33 additions & 0 deletions tests/baselines/reference/controlFlowGenericTypes.types
Expand Up @@ -355,3 +355,36 @@ function get<K extends keyof A>(key: K, obj: A): number {

};

// Repro from #44093

class EventEmitter<ET> {
>EventEmitter : EventEmitter<ET>

off<K extends keyof ET>(...args: [K, number] | [unknown, string]):void {}
>off : <K extends keyof ET>(...args: [K, number] | [unknown, string]) => void
>args : [K, number] | [unknown, string]
}
function once<ET, T extends EventEmitter<ET>>(emittingObject: T, eventName: keyof ET): void {
>once : <ET, T extends EventEmitter<ET>>(emittingObject: T, eventName: keyof ET) => void
>emittingObject : T
>eventName : keyof ET

emittingObject.off(eventName, 0);
>emittingObject.off(eventName, 0) : void
>emittingObject.off : <K extends keyof ET>(...args: [unknown, string] | [K, number]) => void
>emittingObject : T
>off : <K extends keyof ET>(...args: [unknown, string] | [K, number]) => void
>eventName : keyof ET
>0 : 0

emittingObject.off(eventName as typeof eventName, 0);
>emittingObject.off(eventName as typeof eventName, 0) : void
>emittingObject.off : <K extends keyof ET>(...args: [unknown, string] | [K, number]) => void
>emittingObject : T
>off : <K extends keyof ET>(...args: [unknown, string] | [K, number]) => void
>eventName as typeof eventName : keyof ET
>eventName : keyof ET
>eventName : keyof ET
>0 : 0
}

10 changes: 10 additions & 0 deletions tests/cases/conformance/controlFlow/controlFlowGenericTypes.ts
Expand Up @@ -129,3 +129,13 @@ function get<K extends keyof A>(key: K, obj: A): number {
}
return 0;
};

// Repro from #44093

class EventEmitter<ET> {
off<K extends keyof ET>(...args: [K, number] | [unknown, string]):void {}
}
function once<ET, T extends EventEmitter<ET>>(emittingObject: T, eventName: keyof ET): void {
emittingObject.off(eventName, 0);
emittingObject.off(eventName as typeof eventName, 0);
}

0 comments on commit e67da8a

Please sign in to comment.