Skip to content

Commit 688e9bc

Browse files
authored
Merge pull request #10234 from Microsoft/correct-this-in-tuple-type-parameter-constraints
Correct this in tuple type parameter constraints
2 parents fa991b5 + 4087808 commit 688e9bc

6 files changed

+196
-6
lines changed

src/compiler/checker.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1538,8 +1538,8 @@ namespace ts {
15381538

15391539
function createType(flags: TypeFlags): Type {
15401540
const result = new Type(checker, flags);
1541-
result.id = typeCount;
15421541
typeCount++;
1542+
result.id = typeCount;
15431543
return result;
15441544
}
15451545

@@ -4000,6 +4000,9 @@ namespace ts {
40004000
return createTypeReference((<TypeReference>type).target,
40014001
concatenate((<TypeReference>type).typeArguments, [thisArgument || (<TypeReference>type).target.thisType]));
40024002
}
4003+
if (type.flags & TypeFlags.Tuple) {
4004+
return createTupleType((type as TupleType).elementTypes, thisArgument);
4005+
}
40034006
return type;
40044007
}
40054008

@@ -4103,7 +4106,8 @@ namespace ts {
41034106
function resolveTupleTypeMembers(type: TupleType) {
41044107
const arrayElementType = getUnionType(type.elementTypes);
41054108
// Make the tuple type itself the 'this' type by including an extra type argument
4106-
const arrayType = resolveStructuredTypeMembers(createTypeFromGenericGlobalType(globalArrayType, [arrayElementType, type]));
4109+
// (Unless it's provided in the case that the tuple is a type parameter constraint)
4110+
const arrayType = resolveStructuredTypeMembers(createTypeFromGenericGlobalType(globalArrayType, [arrayElementType, type.thisType || type]));
41074111
const members = createTupleTypeMemberSymbols(type.elementTypes);
41084112
addInheritedMembers(members, arrayType.properties);
41094113
setObjectTypeMembers(type, members, arrayType.callSignatures, arrayType.constructSignatures, arrayType.stringIndexInfo, arrayType.numberIndexInfo);
@@ -5230,15 +5234,16 @@ namespace ts {
52305234
return links.resolvedType;
52315235
}
52325236

5233-
function createTupleType(elementTypes: Type[]) {
5234-
const id = getTypeListId(elementTypes);
5235-
return tupleTypes[id] || (tupleTypes[id] = createNewTupleType(elementTypes));
5237+
function createTupleType(elementTypes: Type[], thisType?: Type) {
5238+
const id = getTypeListId(elementTypes) + "," + (thisType ? thisType.id : 0);
5239+
return tupleTypes[id] || (tupleTypes[id] = createNewTupleType(elementTypes, thisType));
52365240
}
52375241

5238-
function createNewTupleType(elementTypes: Type[]) {
5242+
function createNewTupleType(elementTypes: Type[], thisType?: Type) {
52395243
const propagatedFlags = getPropagatingFlagsOfTypes(elementTypes, /*excludeKinds*/ 0);
52405244
const type = <TupleType>createObjectType(TypeFlags.Tuple | propagatedFlags);
52415245
type.elementTypes = elementTypes;
5246+
type.thisType = thisType;
52425247
return type;
52435248
}
52445249

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2371,6 +2371,7 @@ namespace ts {
23712371

23722372
export interface TupleType extends ObjectType {
23732373
elementTypes: Type[]; // Element types
2374+
thisType?: Type; // This-type of tuple (only needed for tuples that are constraints of type parameters)
23742375
}
23752376

23762377
export interface UnionOrIntersectionType extends Type {
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//// [thisInTupleTypeParameterConstraints.ts]
2+
/// <reference no-default-lib="true"/>
3+
4+
interface Boolean {}
5+
interface IArguments {}
6+
interface Function {}
7+
interface Number {}
8+
interface RegExp {}
9+
interface Object {}
10+
interface String {}
11+
12+
interface Array<T> {
13+
// 4 methods will run out of memory if this-types are not instantiated
14+
// correctly for tuple types that are type parameter constraints
15+
map<U>(arg: this): void;
16+
reduceRight<U>(arg: this): void;
17+
reduce<U>(arg: this): void;
18+
reduce2<U>(arg: this): void;
19+
}
20+
21+
declare function f<T extends [(x: number) => number]>(a: T): void;
22+
let x: [(x: number) => number];
23+
f(x);
24+
25+
26+
//// [thisInTupleTypeParameterConstraints.js]
27+
/// <reference no-default-lib="true"/>
28+
var x;
29+
f(x);
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
=== tests/cases/compiler/thisInTupleTypeParameterConstraints.ts ===
2+
/// <reference no-default-lib="true"/>
3+
4+
interface Boolean {}
5+
>Boolean : Symbol(Boolean, Decl(thisInTupleTypeParameterConstraints.ts, 0, 0))
6+
7+
interface IArguments {}
8+
>IArguments : Symbol(IArguments, Decl(thisInTupleTypeParameterConstraints.ts, 2, 20))
9+
10+
interface Function {}
11+
>Function : Symbol(Function, Decl(thisInTupleTypeParameterConstraints.ts, 3, 23))
12+
13+
interface Number {}
14+
>Number : Symbol(Number, Decl(thisInTupleTypeParameterConstraints.ts, 4, 21))
15+
16+
interface RegExp {}
17+
>RegExp : Symbol(RegExp, Decl(thisInTupleTypeParameterConstraints.ts, 5, 19))
18+
19+
interface Object {}
20+
>Object : Symbol(Object, Decl(thisInTupleTypeParameterConstraints.ts, 6, 19))
21+
22+
interface String {}
23+
>String : Symbol(String, Decl(thisInTupleTypeParameterConstraints.ts, 7, 19))
24+
25+
interface Array<T> {
26+
>Array : Symbol(Array, Decl(thisInTupleTypeParameterConstraints.ts, 8, 19))
27+
>T : Symbol(T, Decl(thisInTupleTypeParameterConstraints.ts, 10, 16))
28+
29+
// 4 methods will run out of memory if this-types are not instantiated
30+
// correctly for tuple types that are type parameter constraints
31+
map<U>(arg: this): void;
32+
>map : Symbol(Array.map, Decl(thisInTupleTypeParameterConstraints.ts, 10, 20))
33+
>U : Symbol(U, Decl(thisInTupleTypeParameterConstraints.ts, 13, 8))
34+
>arg : Symbol(arg, Decl(thisInTupleTypeParameterConstraints.ts, 13, 11))
35+
36+
reduceRight<U>(arg: this): void;
37+
>reduceRight : Symbol(Array.reduceRight, Decl(thisInTupleTypeParameterConstraints.ts, 13, 28))
38+
>U : Symbol(U, Decl(thisInTupleTypeParameterConstraints.ts, 14, 16))
39+
>arg : Symbol(arg, Decl(thisInTupleTypeParameterConstraints.ts, 14, 19))
40+
41+
reduce<U>(arg: this): void;
42+
>reduce : Symbol(Array.reduce, Decl(thisInTupleTypeParameterConstraints.ts, 14, 36))
43+
>U : Symbol(U, Decl(thisInTupleTypeParameterConstraints.ts, 15, 11))
44+
>arg : Symbol(arg, Decl(thisInTupleTypeParameterConstraints.ts, 15, 14))
45+
46+
reduce2<U>(arg: this): void;
47+
>reduce2 : Symbol(Array.reduce2, Decl(thisInTupleTypeParameterConstraints.ts, 15, 31))
48+
>U : Symbol(U, Decl(thisInTupleTypeParameterConstraints.ts, 16, 12))
49+
>arg : Symbol(arg, Decl(thisInTupleTypeParameterConstraints.ts, 16, 15))
50+
}
51+
52+
declare function f<T extends [(x: number) => number]>(a: T): void;
53+
>f : Symbol(f, Decl(thisInTupleTypeParameterConstraints.ts, 17, 1))
54+
>T : Symbol(T, Decl(thisInTupleTypeParameterConstraints.ts, 19, 19))
55+
>x : Symbol(x, Decl(thisInTupleTypeParameterConstraints.ts, 19, 31))
56+
>a : Symbol(a, Decl(thisInTupleTypeParameterConstraints.ts, 19, 54))
57+
>T : Symbol(T, Decl(thisInTupleTypeParameterConstraints.ts, 19, 19))
58+
59+
let x: [(x: number) => number];
60+
>x : Symbol(x, Decl(thisInTupleTypeParameterConstraints.ts, 20, 3))
61+
>x : Symbol(x, Decl(thisInTupleTypeParameterConstraints.ts, 20, 9))
62+
63+
f(x);
64+
>f : Symbol(f, Decl(thisInTupleTypeParameterConstraints.ts, 17, 1))
65+
>x : Symbol(x, Decl(thisInTupleTypeParameterConstraints.ts, 20, 3))
66+
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
=== tests/cases/compiler/thisInTupleTypeParameterConstraints.ts ===
2+
/// <reference no-default-lib="true"/>
3+
4+
interface Boolean {}
5+
>Boolean : Boolean
6+
7+
interface IArguments {}
8+
>IArguments : IArguments
9+
10+
interface Function {}
11+
>Function : Function
12+
13+
interface Number {}
14+
>Number : Number
15+
16+
interface RegExp {}
17+
>RegExp : RegExp
18+
19+
interface Object {}
20+
>Object : Object
21+
22+
interface String {}
23+
>String : String
24+
25+
interface Array<T> {
26+
>Array : T[]
27+
>T : T
28+
29+
// 4 methods will run out of memory if this-types are not instantiated
30+
// correctly for tuple types that are type parameter constraints
31+
map<U>(arg: this): void;
32+
>map : <U>(arg: this) => void
33+
>U : U
34+
>arg : this
35+
36+
reduceRight<U>(arg: this): void;
37+
>reduceRight : <U>(arg: this) => void
38+
>U : U
39+
>arg : this
40+
41+
reduce<U>(arg: this): void;
42+
>reduce : <U>(arg: this) => void
43+
>U : U
44+
>arg : this
45+
46+
reduce2<U>(arg: this): void;
47+
>reduce2 : <U>(arg: this) => void
48+
>U : U
49+
>arg : this
50+
}
51+
52+
declare function f<T extends [(x: number) => number]>(a: T): void;
53+
>f : <T extends [(x: number) => number]>(a: T) => void
54+
>T : T
55+
>x : number
56+
>a : T
57+
>T : T
58+
59+
let x: [(x: number) => number];
60+
>x : [(x: number) => number]
61+
>x : number
62+
63+
f(x);
64+
>f(x) : void
65+
>f : <T extends [(x: number) => number]>(a: T) => void
66+
>x : [(x: number) => number]
67+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/// <reference no-default-lib="true"/>
2+
3+
interface Boolean {}
4+
interface IArguments {}
5+
interface Function {}
6+
interface Number {}
7+
interface RegExp {}
8+
interface Object {}
9+
interface String {}
10+
11+
interface Array<T> {
12+
// 4 methods will run out of memory if this-types are not instantiated
13+
// correctly for tuple types that are type parameter constraints
14+
map<U>(arg: this): void;
15+
reduceRight<U>(arg: this): void;
16+
reduce<U>(arg: this): void;
17+
reduce2<U>(arg: this): void;
18+
}
19+
20+
declare function f<T extends [(x: number) => number]>(a: T): void;
21+
let x: [(x: number) => number];
22+
f(x);

0 commit comments

Comments
 (0)