Skip to content

Commit dbab6eb

Browse files
bentongxyzBenjamin Tong
and
Benjamin Tong
authored
fix #49235 Objects that pass the spread syntax can no longer be assigned to assignable types. (#49337)
* fix issue 49235 * update code with suggested changes Co-authored-by: Benjamin Tong <[email protected]>
1 parent 4c1e8f2 commit dbab6eb

File tree

5 files changed

+155
-1
lines changed

5 files changed

+155
-1
lines changed

src/compiler/checker.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -21455,14 +21455,17 @@ namespace ts {
2145521455
* with no call or construct signatures.
2145621456
*/
2145721457
function isObjectTypeWithInferableIndex(type: Type): boolean {
21458+
const objectFlags = getObjectFlags(type);
2145821459
return type.flags & TypeFlags.Intersection
2145921460
? every((type as IntersectionType).types, isObjectTypeWithInferableIndex)
2146021461
: !!(
2146121462
type.symbol
2146221463
&& (type.symbol.flags & (SymbolFlags.ObjectLiteral | SymbolFlags.TypeLiteral | SymbolFlags.Enum | SymbolFlags.ValueModule)) !== 0
2146321464
&& !(type.symbol.flags & SymbolFlags.Class)
2146421465
&& !typeHasCallOrConstructSignatures(type)
21465-
) || !!(getObjectFlags(type) & ObjectFlags.ReverseMapped && isObjectTypeWithInferableIndex((type as ReverseMappedType).source));
21466+
) || !!(
21467+
objectFlags & ObjectFlags.ObjectRestType
21468+
) || !!(objectFlags & ObjectFlags.ReverseMapped && isObjectTypeWithInferableIndex((type as ReverseMappedType).source));
2146621469
}
2146721470

2146821471
function createSymbolWithType(source: Symbol, type: Type | undefined) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//// [restElementAssignable.ts]
2+
{
3+
const { ...props } = {};
4+
// Use to fail
5+
const t1: { [x: symbol]: unknown } = props;
6+
// Working equivalent
7+
const t2: { [x: symbol]: unknown } = {};
8+
}
9+
10+
{
11+
const { ...props } = { a: 1, b: false, c: "str" };
12+
// Use to fail
13+
const t1: { [x: string]: number | boolean | string } = props;
14+
// Working equivalent
15+
const t2: { [x: string]: number | boolean | string } = { a: 1, b: false, c: "str" };;
16+
}
17+
18+
19+
//// [restElementAssignable.js]
20+
"use strict";
21+
var __rest = (this && this.__rest) || function (s, e) {
22+
var t = {};
23+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
24+
t[p] = s[p];
25+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
26+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
27+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
28+
t[p[i]] = s[p[i]];
29+
}
30+
return t;
31+
};
32+
{
33+
var props = __rest({}, []);
34+
// Use to fail
35+
var t1 = props;
36+
// Working equivalent
37+
var t2 = {};
38+
}
39+
{
40+
var props = __rest({ a: 1, b: false, c: "str" }, []);
41+
// Use to fail
42+
var t1 = props;
43+
// Working equivalent
44+
var t2 = { a: 1, b: false, c: "str" };
45+
;
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
=== tests/cases/compiler/restElementAssignable.ts ===
2+
{
3+
const { ...props } = {};
4+
>props : Symbol(props, Decl(restElementAssignable.ts, 1, 11))
5+
6+
// Use to fail
7+
const t1: { [x: symbol]: unknown } = props;
8+
>t1 : Symbol(t1, Decl(restElementAssignable.ts, 3, 9))
9+
>x : Symbol(x, Decl(restElementAssignable.ts, 3, 17))
10+
>props : Symbol(props, Decl(restElementAssignable.ts, 1, 11))
11+
12+
// Working equivalent
13+
const t2: { [x: symbol]: unknown } = {};
14+
>t2 : Symbol(t2, Decl(restElementAssignable.ts, 5, 9))
15+
>x : Symbol(x, Decl(restElementAssignable.ts, 5, 17))
16+
}
17+
18+
{
19+
const { ...props } = { a: 1, b: false, c: "str" };
20+
>props : Symbol(props, Decl(restElementAssignable.ts, 9, 11))
21+
>a : Symbol(a, Decl(restElementAssignable.ts, 9, 26))
22+
>b : Symbol(b, Decl(restElementAssignable.ts, 9, 32))
23+
>c : Symbol(c, Decl(restElementAssignable.ts, 9, 42))
24+
25+
// Use to fail
26+
const t1: { [x: string]: number | boolean | string } = props;
27+
>t1 : Symbol(t1, Decl(restElementAssignable.ts, 11, 9))
28+
>x : Symbol(x, Decl(restElementAssignable.ts, 11, 17))
29+
>props : Symbol(props, Decl(restElementAssignable.ts, 9, 11))
30+
31+
// Working equivalent
32+
const t2: { [x: string]: number | boolean | string } = { a: 1, b: false, c: "str" };;
33+
>t2 : Symbol(t2, Decl(restElementAssignable.ts, 13, 9))
34+
>x : Symbol(x, Decl(restElementAssignable.ts, 13, 17))
35+
>a : Symbol(a, Decl(restElementAssignable.ts, 13, 60))
36+
>b : Symbol(b, Decl(restElementAssignable.ts, 13, 66))
37+
>c : Symbol(c, Decl(restElementAssignable.ts, 13, 76))
38+
}
39+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
=== tests/cases/compiler/restElementAssignable.ts ===
2+
{
3+
const { ...props } = {};
4+
>props : {}
5+
>{} : {}
6+
7+
// Use to fail
8+
const t1: { [x: symbol]: unknown } = props;
9+
>t1 : { [x: symbol]: unknown; }
10+
>x : symbol
11+
>props : {}
12+
13+
// Working equivalent
14+
const t2: { [x: symbol]: unknown } = {};
15+
>t2 : { [x: symbol]: unknown; }
16+
>x : symbol
17+
>{} : {}
18+
}
19+
20+
{
21+
const { ...props } = { a: 1, b: false, c: "str" };
22+
>props : { a: number; b: boolean; c: string; }
23+
>{ a: 1, b: false, c: "str" } : { a: number; b: boolean; c: string; }
24+
>a : number
25+
>1 : 1
26+
>b : boolean
27+
>false : false
28+
>c : string
29+
>"str" : "str"
30+
31+
// Use to fail
32+
const t1: { [x: string]: number | boolean | string } = props;
33+
>t1 : { [x: string]: string | number | boolean; }
34+
>x : string
35+
>props : { a: number; b: boolean; c: string; }
36+
37+
// Working equivalent
38+
const t2: { [x: string]: number | boolean | string } = { a: 1, b: false, c: "str" };;
39+
>t2 : { [x: string]: string | number | boolean; }
40+
>x : string
41+
>{ a: 1, b: false, c: "str" } : { a: number; b: false; c: string; }
42+
>a : number
43+
>1 : 1
44+
>b : false
45+
>false : false
46+
>c : string
47+
>"str" : "str"
48+
}
49+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// @strict: true
2+
3+
{
4+
const { ...props } = {};
5+
// Use to fail
6+
const t1: { [x: symbol]: unknown } = props;
7+
// Working equivalent
8+
const t2: { [x: symbol]: unknown } = {};
9+
}
10+
11+
{
12+
const { ...props } = { a: 1, b: false, c: "str" };
13+
// Use to fail
14+
const t1: { [x: string]: number | boolean | string } = props;
15+
// Working equivalent
16+
const t2: { [x: string]: number | boolean | string } = { a: 1, b: false, c: "str" };;
17+
}

0 commit comments

Comments
 (0)