Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21455,14 +21455,17 @@ namespace ts {
* with no call or construct signatures.
*/
function isObjectTypeWithInferableIndex(type: Type): boolean {
const objectFlags = getObjectFlags(type);
return type.flags & TypeFlags.Intersection
? every((type as IntersectionType).types, isObjectTypeWithInferableIndex)
: !!(
type.symbol
&& (type.symbol.flags & (SymbolFlags.ObjectLiteral | SymbolFlags.TypeLiteral | SymbolFlags.Enum | SymbolFlags.ValueModule)) !== 0
&& !(type.symbol.flags & SymbolFlags.Class)
&& !typeHasCallOrConstructSignatures(type)
) || !!(getObjectFlags(type) & ObjectFlags.ReverseMapped && isObjectTypeWithInferableIndex((type as ReverseMappedType).source));
) || !!(
objectFlags & ObjectFlags.ObjectRestType
) || !!(objectFlags & ObjectFlags.ReverseMapped && isObjectTypeWithInferableIndex((type as ReverseMappedType).source));
}

function createSymbolWithType(source: Symbol, type: Type | undefined) {
Expand Down
46 changes: 46 additions & 0 deletions tests/baselines/reference/restElementAssignable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//// [restElementAssignable.ts]
{
const { ...props } = {};
// Use to fail
const t1: { [x: symbol]: unknown } = props;
// Working equivalent
const t2: { [x: symbol]: unknown } = {};
}

{
const { ...props } = { a: 1, b: false, c: "str" };
// Use to fail
const t1: { [x: string]: number | boolean | string } = props;
// Working equivalent
const t2: { [x: string]: number | boolean | string } = { a: 1, b: false, c: "str" };;
}


//// [restElementAssignable.js]
"use strict";
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
{
var props = __rest({}, []);
// Use to fail
var t1 = props;
// Working equivalent
var t2 = {};
}
{
var props = __rest({ a: 1, b: false, c: "str" }, []);
// Use to fail
var t1 = props;
// Working equivalent
var t2 = { a: 1, b: false, c: "str" };
;
}
39 changes: 39 additions & 0 deletions tests/baselines/reference/restElementAssignable.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
=== tests/cases/compiler/restElementAssignable.ts ===
{
const { ...props } = {};
>props : Symbol(props, Decl(restElementAssignable.ts, 1, 11))

// Use to fail
const t1: { [x: symbol]: unknown } = props;
>t1 : Symbol(t1, Decl(restElementAssignable.ts, 3, 9))
>x : Symbol(x, Decl(restElementAssignable.ts, 3, 17))
>props : Symbol(props, Decl(restElementAssignable.ts, 1, 11))

// Working equivalent
const t2: { [x: symbol]: unknown } = {};
>t2 : Symbol(t2, Decl(restElementAssignable.ts, 5, 9))
>x : Symbol(x, Decl(restElementAssignable.ts, 5, 17))
}

{
const { ...props } = { a: 1, b: false, c: "str" };
>props : Symbol(props, Decl(restElementAssignable.ts, 9, 11))
>a : Symbol(a, Decl(restElementAssignable.ts, 9, 26))
>b : Symbol(b, Decl(restElementAssignable.ts, 9, 32))
>c : Symbol(c, Decl(restElementAssignable.ts, 9, 42))

// Use to fail
const t1: { [x: string]: number | boolean | string } = props;
>t1 : Symbol(t1, Decl(restElementAssignable.ts, 11, 9))
>x : Symbol(x, Decl(restElementAssignable.ts, 11, 17))
>props : Symbol(props, Decl(restElementAssignable.ts, 9, 11))

// Working equivalent
const t2: { [x: string]: number | boolean | string } = { a: 1, b: false, c: "str" };;
>t2 : Symbol(t2, Decl(restElementAssignable.ts, 13, 9))
>x : Symbol(x, Decl(restElementAssignable.ts, 13, 17))
>a : Symbol(a, Decl(restElementAssignable.ts, 13, 60))
>b : Symbol(b, Decl(restElementAssignable.ts, 13, 66))
>c : Symbol(c, Decl(restElementAssignable.ts, 13, 76))
}

49 changes: 49 additions & 0 deletions tests/baselines/reference/restElementAssignable.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
=== tests/cases/compiler/restElementAssignable.ts ===
{
const { ...props } = {};
>props : {}
>{} : {}

// Use to fail
const t1: { [x: symbol]: unknown } = props;
>t1 : { [x: symbol]: unknown; }
>x : symbol
>props : {}

// Working equivalent
const t2: { [x: symbol]: unknown } = {};
>t2 : { [x: symbol]: unknown; }
>x : symbol
>{} : {}
}

{
const { ...props } = { a: 1, b: false, c: "str" };
>props : { a: number; b: boolean; c: string; }
>{ a: 1, b: false, c: "str" } : { a: number; b: boolean; c: string; }
>a : number
>1 : 1
>b : boolean
>false : false
>c : string
>"str" : "str"

// Use to fail
const t1: { [x: string]: number | boolean | string } = props;
>t1 : { [x: string]: string | number | boolean; }
>x : string
>props : { a: number; b: boolean; c: string; }

// Working equivalent
const t2: { [x: string]: number | boolean | string } = { a: 1, b: false, c: "str" };;
>t2 : { [x: string]: string | number | boolean; }
>x : string
>{ a: 1, b: false, c: "str" } : { a: number; b: false; c: string; }
>a : number
>1 : 1
>b : false
>false : false
>c : string
>"str" : "str"
}

17 changes: 17 additions & 0 deletions tests/cases/compiler/restElementAssignable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// @strict: true

{
const { ...props } = {};
// Use to fail
const t1: { [x: symbol]: unknown } = props;
// Working equivalent
const t2: { [x: symbol]: unknown } = {};
}

{
const { ...props } = { a: 1, b: false, c: "str" };
// Use to fail
const t1: { [x: string]: number | boolean | string } = props;
// Working equivalent
const t2: { [x: string]: number | boolean | string } = { a: 1, b: false, c: "str" };;
}