diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c2f5d4862f0f2..f03bee8227ce9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -21455,6 +21455,7 @@ 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) : !!( @@ -21462,7 +21463,9 @@ namespace ts { && (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) { diff --git a/tests/baselines/reference/restElementAssignable.js b/tests/baselines/reference/restElementAssignable.js new file mode 100644 index 0000000000000..56fc584422905 --- /dev/null +++ b/tests/baselines/reference/restElementAssignable.js @@ -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" }; + ; +} diff --git a/tests/baselines/reference/restElementAssignable.symbols b/tests/baselines/reference/restElementAssignable.symbols new file mode 100644 index 0000000000000..01bbeead6cab1 --- /dev/null +++ b/tests/baselines/reference/restElementAssignable.symbols @@ -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)) +} + diff --git a/tests/baselines/reference/restElementAssignable.types b/tests/baselines/reference/restElementAssignable.types new file mode 100644 index 0000000000000..3407bc77e780d --- /dev/null +++ b/tests/baselines/reference/restElementAssignable.types @@ -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" +} + diff --git a/tests/cases/compiler/restElementAssignable.ts b/tests/cases/compiler/restElementAssignable.ts new file mode 100644 index 0000000000000..ece77cd661688 --- /dev/null +++ b/tests/cases/compiler/restElementAssignable.ts @@ -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" };; +}