From 111a88d4f8c296e5464a0ebf63d66ce8fabb97dc Mon Sep 17 00:00:00 2001 From: Benjamin Tong Date: Wed, 1 Jun 2022 08:05:06 +0000 Subject: [PATCH 1/2] fix issue 49235 --- src/compiler/checker.ts | 4 ++ .../reference/restElementAssignable.js | 46 +++++++++++++++++ .../reference/restElementAssignable.symbols | 39 +++++++++++++++ .../reference/restElementAssignable.types | 49 +++++++++++++++++++ tests/cases/compiler/restElementAssignable.ts | 17 +++++++ 5 files changed, 155 insertions(+) create mode 100644 tests/baselines/reference/restElementAssignable.js create mode 100644 tests/baselines/reference/restElementAssignable.symbols create mode 100644 tests/baselines/reference/restElementAssignable.types create mode 100644 tests/cases/compiler/restElementAssignable.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ec43221b1f7a4..a816911d5b88f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -21463,6 +21463,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) : !!( @@ -21470,6 +21471,9 @@ namespace ts { && (type.symbol.flags & (SymbolFlags.ObjectLiteral | SymbolFlags.TypeLiteral | SymbolFlags.Enum | SymbolFlags.ValueModule)) !== 0 && !(type.symbol.flags & SymbolFlags.Class) && !typeHasCallOrConstructSignatures(type) + ) || !!( + objectFlags + && objectFlags & ObjectFlags.ObjectRestType ) || !!(getObjectFlags(type) & ObjectFlags.ReverseMapped && isObjectTypeWithInferableIndex((type as ReverseMappedType).source)); } 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" };; +} From 10c8f15a7203730be852082b4a391ac4b8f35489 Mon Sep 17 00:00:00 2001 From: Benjamin Tong Date: Fri, 10 Jun 2022 23:22:49 +0800 Subject: [PATCH 2/2] update code with suggested changes --- src/compiler/checker.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8091cc3fc4f60..f03bee8227ce9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -21464,9 +21464,8 @@ namespace ts { && !(type.symbol.flags & SymbolFlags.Class) && !typeHasCallOrConstructSignatures(type) ) || !!( - objectFlags - && objectFlags & ObjectFlags.ObjectRestType - ) || !!(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) {