Skip to content

Commit 966d986

Browse files
authored
Properly instantiate object types created from rest parameters (microsoft#34826)
* Anonymous types of rest variable declarations need instantiation * Add regression test * Accept new baselines * Accept new API baselines
1 parent 56cad36 commit 966d986

File tree

8 files changed

+127
-6
lines changed

8 files changed

+127
-6
lines changed

src/compiler/checker.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6657,7 +6657,9 @@ namespace ts {
66576657
}
66586658
const stringIndexInfo = getIndexInfoOfType(source, IndexKind.String);
66596659
const numberIndexInfo = getIndexInfoOfType(source, IndexKind.Number);
6660-
return createAnonymousType(symbol, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
6660+
const result = createAnonymousType(symbol, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
6661+
result.objectFlags |= ObjectFlags.ObjectRestType;
6662+
return result;
66616663
}
66626664

66636665
// Determine the control flow type associated with a destructuring declaration or assignment. The following
@@ -17240,7 +17242,7 @@ namespace ts {
1724017242
return !!(type.flags & TypeFlags.Instantiable ||
1724117243
objectFlags & ObjectFlags.Reference && ((<TypeReference>type).node || forEach(getTypeArguments(<TypeReference>type), couldContainTypeVariables)) ||
1724217244
objectFlags & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && type.symbol.declarations ||
17243-
objectFlags & ObjectFlags.Mapped ||
17245+
objectFlags & (ObjectFlags.Mapped | ObjectFlags.ObjectRestType) ||
1724417246
type.flags & TypeFlags.UnionOrIntersection && !(type.flags & TypeFlags.EnumLiteral) && couldUnionOrIntersectionContainTypeVariables(<UnionOrIntersectionType>type));
1724517247
}
1724617248

src/compiler/types.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4352,14 +4352,15 @@ namespace ts {
43524352
JSLiteral = 1 << 14, // Object type declared in JS - disables errors on read/write of nonexisting members
43534353
FreshLiteral = 1 << 15, // Fresh object literal
43544354
ArrayLiteral = 1 << 16, // Originates in an array literal
4355+
ObjectRestType = 1 << 17, // Originates in object rest declaration
43554356
/* @internal */
4356-
PrimitiveUnion = 1 << 17, // Union of only primitive types
4357+
PrimitiveUnion = 1 << 18, // Union of only primitive types
43574358
/* @internal */
4358-
ContainsWideningType = 1 << 18, // Type is or contains undefined or null widening type
4359+
ContainsWideningType = 1 << 19, // Type is or contains undefined or null widening type
43594360
/* @internal */
4360-
ContainsObjectOrArrayLiteral = 1 << 19, // Type is or contains object literal type
4361+
ContainsObjectOrArrayLiteral = 1 << 20, // Type is or contains object literal type
43614362
/* @internal */
4362-
NonInferrableType = 1 << 20, // Type is or contains anyFunctionType or silentNeverType
4363+
NonInferrableType = 1 << 21, // Type is or contains anyFunctionType or silentNeverType
43634364
ClassOrInterface = Class | Interface,
43644365
/* @internal */
43654366
RequiresWidening = ContainsWideningType | ContainsObjectOrArrayLiteral,

tests/baselines/reference/api/tsserverlibrary.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2378,6 +2378,7 @@ declare namespace ts {
23782378
JSLiteral = 16384,
23792379
FreshLiteral = 32768,
23802380
ArrayLiteral = 65536,
2381+
ObjectRestType = 131072,
23812382
ClassOrInterface = 3,
23822383
}
23832384
export interface ObjectType extends Type {

tests/baselines/reference/api/typescript.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2378,6 +2378,7 @@ declare namespace ts {
23782378
JSLiteral = 16384,
23792379
FreshLiteral = 32768,
23802380
ArrayLiteral = 65536,
2381+
ObjectRestType = 131072,
23812382
ClassOrInterface = 3,
23822383
}
23832384
export interface ObjectType extends Type {
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//// [restParameterTypeInstantiation.ts]
2+
// Repro from #33823
3+
4+
interface TestGeneric<TG> {
5+
f: string
6+
g: TG
7+
}
8+
9+
const removeF = <TX>({ f, ...rest }: TestGeneric<TX>) => {
10+
return rest
11+
}
12+
13+
const result: number = removeF<number>({ f: '', g: 3 }).g
14+
15+
16+
//// [restParameterTypeInstantiation.js]
17+
"use strict";
18+
// Repro from #33823
19+
var __rest = (this && this.__rest) || function (s, e) {
20+
var t = {};
21+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
22+
t[p] = s[p];
23+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
24+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
25+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
26+
t[p[i]] = s[p[i]];
27+
}
28+
return t;
29+
};
30+
var removeF = function (_a) {
31+
var f = _a.f, rest = __rest(_a, ["f"]);
32+
return rest;
33+
};
34+
var result = removeF({ f: '', g: 3 }).g;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
=== tests/cases/compiler/restParameterTypeInstantiation.ts ===
2+
// Repro from #33823
3+
4+
interface TestGeneric<TG> {
5+
>TestGeneric : Symbol(TestGeneric, Decl(restParameterTypeInstantiation.ts, 0, 0))
6+
>TG : Symbol(TG, Decl(restParameterTypeInstantiation.ts, 2, 22))
7+
8+
f: string
9+
>f : Symbol(TestGeneric.f, Decl(restParameterTypeInstantiation.ts, 2, 27))
10+
11+
g: TG
12+
>g : Symbol(TestGeneric.g, Decl(restParameterTypeInstantiation.ts, 3, 11))
13+
>TG : Symbol(TG, Decl(restParameterTypeInstantiation.ts, 2, 22))
14+
}
15+
16+
const removeF = <TX>({ f, ...rest }: TestGeneric<TX>) => {
17+
>removeF : Symbol(removeF, Decl(restParameterTypeInstantiation.ts, 7, 5))
18+
>TX : Symbol(TX, Decl(restParameterTypeInstantiation.ts, 7, 17))
19+
>f : Symbol(f, Decl(restParameterTypeInstantiation.ts, 7, 22))
20+
>rest : Symbol(rest, Decl(restParameterTypeInstantiation.ts, 7, 25))
21+
>TestGeneric : Symbol(TestGeneric, Decl(restParameterTypeInstantiation.ts, 0, 0))
22+
>TX : Symbol(TX, Decl(restParameterTypeInstantiation.ts, 7, 17))
23+
24+
return rest
25+
>rest : Symbol(rest, Decl(restParameterTypeInstantiation.ts, 7, 25))
26+
}
27+
28+
const result: number = removeF<number>({ f: '', g: 3 }).g
29+
>result : Symbol(result, Decl(restParameterTypeInstantiation.ts, 11, 5))
30+
>removeF<number>({ f: '', g: 3 }).g : Symbol(TestGeneric.g, Decl(restParameterTypeInstantiation.ts, 3, 11))
31+
>removeF : Symbol(removeF, Decl(restParameterTypeInstantiation.ts, 7, 5))
32+
>f : Symbol(f, Decl(restParameterTypeInstantiation.ts, 11, 40))
33+
>g : Symbol(g, Decl(restParameterTypeInstantiation.ts, 11, 47))
34+
>g : Symbol(TestGeneric.g, Decl(restParameterTypeInstantiation.ts, 3, 11))
35+
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
=== tests/cases/compiler/restParameterTypeInstantiation.ts ===
2+
// Repro from #33823
3+
4+
interface TestGeneric<TG> {
5+
f: string
6+
>f : string
7+
8+
g: TG
9+
>g : TG
10+
}
11+
12+
const removeF = <TX>({ f, ...rest }: TestGeneric<TX>) => {
13+
>removeF : <TX>({ f, ...rest }: TestGeneric<TX>) => { g: TX; }
14+
><TX>({ f, ...rest }: TestGeneric<TX>) => { return rest} : <TX>({ f, ...rest }: TestGeneric<TX>) => { g: TX; }
15+
>f : string
16+
>rest : { g: TX; }
17+
18+
return rest
19+
>rest : { g: TX; }
20+
}
21+
22+
const result: number = removeF<number>({ f: '', g: 3 }).g
23+
>result : number
24+
>removeF<number>({ f: '', g: 3 }).g : number
25+
>removeF<number>({ f: '', g: 3 }) : { g: number; }
26+
>removeF : <TX>({ f, ...rest }: TestGeneric<TX>) => { g: TX; }
27+
>{ f: '', g: 3 } : { f: string; g: number; }
28+
>f : string
29+
>'' : ""
30+
>g : number
31+
>3 : 3
32+
>g : number
33+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// @strict: true
2+
3+
// Repro from #33823
4+
5+
interface TestGeneric<TG> {
6+
f: string
7+
g: TG
8+
}
9+
10+
const removeF = <TX>({ f, ...rest }: TestGeneric<TX>) => {
11+
return rest
12+
}
13+
14+
const result: number = removeF<number>({ f: '', g: 3 }).g

0 commit comments

Comments
 (0)