From 46e771a020b87c8f2b0a9f0fe8dc1ce23a69f0e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 31 Aug 2023 10:05:11 +0200 Subject: [PATCH] Fixed element access expression writes for divergent write types --- src/compiler/checker.ts | 5 +- src/compiler/utilities.ts | 4 +- .../reference/divergentAccessorsTypes7.js | 6 +- .../divergentAccessorsTypes7.symbols | 12 +- .../reference/divergentAccessorsTypes7.types | 15 +- .../divergentAccessorsTypes8.errors.txt | 174 +++++++ .../divergentAccessorsTypes8.symbols | 345 ++++++++++++++ .../reference/divergentAccessorsTypes8.types | 429 ++++++++++++++++++ .../compiler/divergentAccessorsTypes7.ts | 5 +- .../compiler/divergentAccessorsTypes8.ts | 153 +++++++ ...uickInfoOnElementAccessInWriteLocation1.ts | 8 + ...uickInfoOnElementAccessInWriteLocation2.ts | 8 + ...uickInfoOnElementAccessInWriteLocation3.ts | 8 + ...uickInfoOnElementAccessInWriteLocation4.ts | 11 + ...uickInfoOnElementAccessInWriteLocation5.ts | 11 + 15 files changed, 1182 insertions(+), 12 deletions(-) create mode 100644 tests/baselines/reference/divergentAccessorsTypes8.errors.txt create mode 100644 tests/baselines/reference/divergentAccessorsTypes8.symbols create mode 100644 tests/baselines/reference/divergentAccessorsTypes8.types create mode 100644 tests/cases/compiler/divergentAccessorsTypes8.ts create mode 100644 tests/cases/fourslash/quickInfoOnElementAccessInWriteLocation1.ts create mode 100644 tests/cases/fourslash/quickInfoOnElementAccessInWriteLocation2.ts create mode 100644 tests/cases/fourslash/quickInfoOnElementAccessInWriteLocation3.ts create mode 100644 tests/cases/fourslash/quickInfoOnElementAccessInWriteLocation4.ts create mode 100644 tests/cases/fourslash/quickInfoOnElementAccessInWriteLocation5.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f1eb9d5b7c606..d06de387df462 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -685,6 +685,7 @@ import { isRequireCall, isRestParameter, isRestTypeNode, + isRightSideOfAccessExpression, isRightSideOfQualifiedNameOrPropertyAccess, isRightSideOfQualifiedNameOrPropertyAccessOrJSDocMemberName, isSameEntityName, @@ -17705,7 +17706,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return autoType; } } - const propType = getTypeOfSymbol(prop); + const propType = accessFlags & AccessFlags.Writing ? getWriteTypeOfSymbol(prop) : getTypeOfSymbol(prop); return accessExpression && getAssignmentTargetKind(accessExpression) !== AssignmentKind.Definite ? getFlowTypeOfReference(accessExpression, propType) : accessNode && isIndexedAccessTypeNode(accessNode) && containsMissingType(propType) ? getUnionType([propType, undefinedType]) : propType; @@ -28178,7 +28179,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // to it at the given location. Since we have no control flow information for the // hypothetical reference (control flow information is created and attached by the // binder), we simply return the declared type of the symbol. - return getNonMissingTypeOfSymbol(symbol); + return isRightSideOfAccessExpression(location) && isWriteAccess(location.parent) ? getWriteTypeOfSymbol(symbol) : getNonMissingTypeOfSymbol(symbol); } function getControlFlowContainer(node: Node): Node { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 960494f8a9abe..19528cd516873 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -7239,8 +7239,8 @@ export function isRightSideOfQualifiedNameOrPropertyAccess(node: Node) { /** @internal */ export function isRightSideOfAccessExpression(node: Node) { - return isPropertyAccessExpression(node.parent) && node.parent.name === node - || isElementAccessExpression(node.parent) && node.parent.argumentExpression === node; + return !!node.parent && (isPropertyAccessExpression(node.parent) && node.parent.name === node + || isElementAccessExpression(node.parent) && node.parent.argumentExpression === node); } /** @internal */ diff --git a/tests/baselines/reference/divergentAccessorsTypes7.js b/tests/baselines/reference/divergentAccessorsTypes7.js index ed5cdb501d17b..f5a534f1f7af2 100644 --- a/tests/baselines/reference/divergentAccessorsTypes7.js +++ b/tests/baselines/reference/divergentAccessorsTypes7.js @@ -9,12 +9,12 @@ class Test { get value(): string { return null!; } - + // -- Replacing the getter such that the getter/setter types match, removes the error: // get value(): string | ((item: S) => string) { // return null!; // } - + // -- Or, replacing the setter such that a concrete type is used, removes the error: // set value(value: string | ((item: { property: string }) => string)) {} } @@ -24,6 +24,7 @@ const a = new Test<{ }>(); a.value = (item) => item.property +a['value'] = (item) => item.property //// [divergentAccessorsTypes7.js] @@ -42,3 +43,4 @@ var Test = /** @class */ (function () { }()); var a = new Test(); a.value = function (item) { return item.property; }; +a['value'] = function (item) { return item.property; }; diff --git a/tests/baselines/reference/divergentAccessorsTypes7.symbols b/tests/baselines/reference/divergentAccessorsTypes7.symbols index ea85654577900..18246474b3519 100644 --- a/tests/baselines/reference/divergentAccessorsTypes7.symbols +++ b/tests/baselines/reference/divergentAccessorsTypes7.symbols @@ -18,12 +18,12 @@ class Test { return null!; } - + // -- Replacing the getter such that the getter/setter types match, removes the error: // get value(): string | ((item: S) => string) { // return null!; // } - + // -- Or, replacing the setter such that a concrete type is used, removes the error: // set value(value: string | ((item: { property: string }) => string)) {} } @@ -46,3 +46,11 @@ a.value = (item) => item.property >item : Symbol(item, Decl(divergentAccessorsTypes7.ts, 22, 11)) >property : Symbol(property, Decl(divergentAccessorsTypes7.ts, 18, 20)) +a['value'] = (item) => item.property +>a : Symbol(a, Decl(divergentAccessorsTypes7.ts, 18, 5)) +>'value' : Symbol(Test.value, Decl(divergentAccessorsTypes7.ts, 1, 20), Decl(divergentAccessorsTypes7.ts, 3, 55)) +>item : Symbol(item, Decl(divergentAccessorsTypes7.ts, 23, 14)) +>item.property : Symbol(property, Decl(divergentAccessorsTypes7.ts, 18, 20)) +>item : Symbol(item, Decl(divergentAccessorsTypes7.ts, 23, 14)) +>property : Symbol(property, Decl(divergentAccessorsTypes7.ts, 18, 20)) + diff --git a/tests/baselines/reference/divergentAccessorsTypes7.types b/tests/baselines/reference/divergentAccessorsTypes7.types index 95e494f4d3df5..330eca4a8e2fb 100644 --- a/tests/baselines/reference/divergentAccessorsTypes7.types +++ b/tests/baselines/reference/divergentAccessorsTypes7.types @@ -17,12 +17,12 @@ class Test { return null!; >null! : null } - + // -- Replacing the getter such that the getter/setter types match, removes the error: // get value(): string | ((item: S) => string) { // return null!; // } - + // -- Or, replacing the setter such that a concrete type is used, removes the error: // set value(value: string | ((item: { property: string }) => string)) {} } @@ -48,3 +48,14 @@ a.value = (item) => item.property >item : { property: string; } >property : string +a['value'] = (item) => item.property +>a['value'] = (item) => item.property : (item: { property: string; }) => string +>a['value'] : string | ((item: { property: string; }) => string) +>a : Test<{ property: string; }> +>'value' : "value" +>(item) => item.property : (item: { property: string; }) => string +>item : { property: string; } +>item.property : string +>item : { property: string; } +>property : string + diff --git a/tests/baselines/reference/divergentAccessorsTypes8.errors.txt b/tests/baselines/reference/divergentAccessorsTypes8.errors.txt new file mode 100644 index 0000000000000..ab22c1b5dd76d --- /dev/null +++ b/tests/baselines/reference/divergentAccessorsTypes8.errors.txt @@ -0,0 +1,174 @@ +divergentAccessorsTypes8.ts(20,1): error TS2322: Type 'CSSStyleDeclaration' is not assignable to type 'string'. +divergentAccessorsTypes8.ts(86,1): error TS2322: Type 'number' is not assignable to type 'string'. +divergentAccessorsTypes8.ts(124,1): error TS2322: Type '42' is not assignable to type '"hello"'. +divergentAccessorsTypes8.ts(128,1): error TS2322: Type '"hello"' is not assignable to type '42'. +divergentAccessorsTypes8.ts(146,1): error TS2322: Type 'number' is not assignable to type 'boolean'. +divergentAccessorsTypes8.ts(148,1): error TS2322: Type 'string' is not assignable to type 'boolean'. +divergentAccessorsTypes8.ts(149,1): error TS2322: Type 'null' is not assignable to type 'boolean'. + + +==== divergentAccessorsTypes8.ts (7 errors) ==== + export {} + + interface Serializer { + set value(v: string | number | boolean); + get value(): string; + } + declare let box: Serializer; + const v = box['value'] + box['value'] = true; + box['value'] = 42; + box['value'] = "hello"; + + interface Element { + get style(): CSSStyleDeclaration; + set style(cssText: string); + } + + declare const element: Element; + element['style'] = "color: red"; + element['style'] = element.style; + ~~~~~~~~~~~~~~~~ +!!! error TS2322: Type 'CSSStyleDeclaration' is not assignable to type 'string'. + + class One { + get prop1(): string { + return ""; + } + set prop1(s: string | number) {} + + get prop2(): string { + return ""; + } + set prop2(s: string | number) {} + + prop3: number = 42; + + get prop4(): string { + return ""; + } + set prop4(s: string | number) {} + } + + class Two { + get prop1(): string { + return ""; + } + set prop1(s: string | number) {} + + get prop2(): string { + return ""; + } + set prop2(s: string) {} + + get prop3(): string { + return ""; + } + set prop3(s: string | boolean) {} + + get prop4(): string { + return ""; + } + set prop4(s: string | boolean) {} + } + + declare const u1: One | Two; + + u1['prop1'] = 42; + u1['prop1'] = "hello"; + + u1['prop2'] = 42; + u1['prop2'] = "hello"; + + u1['prop3'] = 42; + u1['prop3'] = "hello"; + u1['prop3'] = true; + + u1['prop4'] = 42; + u1['prop4'] = "hello"; + u1['prop4'] = true; + + declare const i: One & Two; + + const iv1 = i['prop1']; + i['prop1'] = 42; + i['prop1'] = "hello"; + + const iv2 = i['prop2']; + i['prop2'] = 42; + ~~~~~~~~~~ +!!! error TS2322: Type 'number' is not assignable to type 'string'. + i['prop2'] = "hello"; + + class Three { + get prop1(): string { + return ""; + } + set prop1(s: string | number) {} + + prop2: number = 42; + } + + class Four { + get prop1(): "hello" { + return "hello"; + } + set prop1(s: "hello" | number) {} + + get prop2(): string { + return ""; + } + set prop2(s: string | 42) {} + } + + class Five { + get prop1(): "hello" { + return "hello"; + } + set prop1(s: "hello" | boolean) {} + + get prop2(): string { + return ""; + } + set prop2(s: string | number | boolean) {} + } + + declare const i2: Three & Four & Five; + + i2['prop1'] = 42; + ~~~~~~~~~~~ +!!! error TS2322: Type '42' is not assignable to type '"hello"'. + i2['prop1'] = "hello"; + + i2['prop2'] = 42; + i2['prop2'] = "hello"; + ~~~~~~~~~~~ +!!! error TS2322: Type '"hello"' is not assignable to type '42'. + + class Six { + get prop1(): boolean | number { + return 42; + } + set prop1(s: boolean | string) {} + + get prop2(): bigint | number { + return 10; + } + set prop2(s: boolean | null) {} + } + + declare const s1: Six + declare const k1: 'prop1' | 'prop2' + + const sv1 = s1[k1] + s1[k1] = 42 + ~~~~~~ +!!! error TS2322: Type 'number' is not assignable to type 'boolean'. + s1[k1] = true + s1[k1] = '' + ~~~~~~ +!!! error TS2322: Type 'string' is not assignable to type 'boolean'. + s1[k1] = null + ~~~~~~ +!!! error TS2322: Type 'null' is not assignable to type 'boolean'. + \ No newline at end of file diff --git a/tests/baselines/reference/divergentAccessorsTypes8.symbols b/tests/baselines/reference/divergentAccessorsTypes8.symbols new file mode 100644 index 0000000000000..e168fbf6fbdad --- /dev/null +++ b/tests/baselines/reference/divergentAccessorsTypes8.symbols @@ -0,0 +1,345 @@ +//// [tests/cases/compiler/divergentAccessorsTypes8.ts] //// + +=== divergentAccessorsTypes8.ts === +export {} + +interface Serializer { +>Serializer : Symbol(Serializer, Decl(divergentAccessorsTypes8.ts, 0, 9)) + + set value(v: string | number | boolean); +>value : Symbol(Serializer.value, Decl(divergentAccessorsTypes8.ts, 2, 22), Decl(divergentAccessorsTypes8.ts, 3, 42)) +>v : Symbol(v, Decl(divergentAccessorsTypes8.ts, 3, 12)) + + get value(): string; +>value : Symbol(Serializer.value, Decl(divergentAccessorsTypes8.ts, 2, 22), Decl(divergentAccessorsTypes8.ts, 3, 42)) +} +declare let box: Serializer; +>box : Symbol(box, Decl(divergentAccessorsTypes8.ts, 6, 11)) +>Serializer : Symbol(Serializer, Decl(divergentAccessorsTypes8.ts, 0, 9)) + +const v = box['value'] +>v : Symbol(v, Decl(divergentAccessorsTypes8.ts, 7, 5)) +>box : Symbol(box, Decl(divergentAccessorsTypes8.ts, 6, 11)) +>'value' : Symbol(Serializer.value, Decl(divergentAccessorsTypes8.ts, 2, 22), Decl(divergentAccessorsTypes8.ts, 3, 42)) + +box['value'] = true; +>box : Symbol(box, Decl(divergentAccessorsTypes8.ts, 6, 11)) +>'value' : Symbol(Serializer.value, Decl(divergentAccessorsTypes8.ts, 2, 22), Decl(divergentAccessorsTypes8.ts, 3, 42)) + +box['value'] = 42; +>box : Symbol(box, Decl(divergentAccessorsTypes8.ts, 6, 11)) +>'value' : Symbol(Serializer.value, Decl(divergentAccessorsTypes8.ts, 2, 22), Decl(divergentAccessorsTypes8.ts, 3, 42)) + +box['value'] = "hello"; +>box : Symbol(box, Decl(divergentAccessorsTypes8.ts, 6, 11)) +>'value' : Symbol(Serializer.value, Decl(divergentAccessorsTypes8.ts, 2, 22), Decl(divergentAccessorsTypes8.ts, 3, 42)) + +interface Element { +>Element : Symbol(Element, Decl(divergentAccessorsTypes8.ts, 10, 23)) + + get style(): CSSStyleDeclaration; +>style : Symbol(Element.style, Decl(divergentAccessorsTypes8.ts, 12, 19), Decl(divergentAccessorsTypes8.ts, 13, 37)) +>CSSStyleDeclaration : Symbol(CSSStyleDeclaration, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) + + set style(cssText: string); +>style : Symbol(Element.style, Decl(divergentAccessorsTypes8.ts, 12, 19), Decl(divergentAccessorsTypes8.ts, 13, 37)) +>cssText : Symbol(cssText, Decl(divergentAccessorsTypes8.ts, 14, 14)) +} + +declare const element: Element; +>element : Symbol(element, Decl(divergentAccessorsTypes8.ts, 17, 13)) +>Element : Symbol(Element, Decl(divergentAccessorsTypes8.ts, 10, 23)) + +element['style'] = "color: red"; +>element : Symbol(element, Decl(divergentAccessorsTypes8.ts, 17, 13)) +>'style' : Symbol(Element.style, Decl(divergentAccessorsTypes8.ts, 12, 19), Decl(divergentAccessorsTypes8.ts, 13, 37)) + +element['style'] = element.style; +>element : Symbol(element, Decl(divergentAccessorsTypes8.ts, 17, 13)) +>'style' : Symbol(Element.style, Decl(divergentAccessorsTypes8.ts, 12, 19), Decl(divergentAccessorsTypes8.ts, 13, 37)) +>element.style : Symbol(Element.style, Decl(divergentAccessorsTypes8.ts, 12, 19), Decl(divergentAccessorsTypes8.ts, 13, 37)) +>element : Symbol(element, Decl(divergentAccessorsTypes8.ts, 17, 13)) +>style : Symbol(Element.style, Decl(divergentAccessorsTypes8.ts, 12, 19), Decl(divergentAccessorsTypes8.ts, 13, 37)) + +class One { +>One : Symbol(One, Decl(divergentAccessorsTypes8.ts, 19, 33)) + + get prop1(): string { +>prop1 : Symbol(One.prop1, Decl(divergentAccessorsTypes8.ts, 21, 11), Decl(divergentAccessorsTypes8.ts, 24, 3)) + + return ""; + } + set prop1(s: string | number) {} +>prop1 : Symbol(One.prop1, Decl(divergentAccessorsTypes8.ts, 21, 11), Decl(divergentAccessorsTypes8.ts, 24, 3)) +>s : Symbol(s, Decl(divergentAccessorsTypes8.ts, 25, 12)) + + get prop2(): string { +>prop2 : Symbol(One.prop2, Decl(divergentAccessorsTypes8.ts, 25, 34), Decl(divergentAccessorsTypes8.ts, 29, 3)) + + return ""; + } + set prop2(s: string | number) {} +>prop2 : Symbol(One.prop2, Decl(divergentAccessorsTypes8.ts, 25, 34), Decl(divergentAccessorsTypes8.ts, 29, 3)) +>s : Symbol(s, Decl(divergentAccessorsTypes8.ts, 30, 12)) + + prop3: number = 42; +>prop3 : Symbol(One.prop3, Decl(divergentAccessorsTypes8.ts, 30, 34)) + + get prop4(): string { +>prop4 : Symbol(One.prop4, Decl(divergentAccessorsTypes8.ts, 32, 21), Decl(divergentAccessorsTypes8.ts, 36, 3)) + + return ""; + } + set prop4(s: string | number) {} +>prop4 : Symbol(One.prop4, Decl(divergentAccessorsTypes8.ts, 32, 21), Decl(divergentAccessorsTypes8.ts, 36, 3)) +>s : Symbol(s, Decl(divergentAccessorsTypes8.ts, 37, 12)) +} + +class Two { +>Two : Symbol(Two, Decl(divergentAccessorsTypes8.ts, 38, 1)) + + get prop1(): string { +>prop1 : Symbol(Two.prop1, Decl(divergentAccessorsTypes8.ts, 40, 11), Decl(divergentAccessorsTypes8.ts, 43, 3)) + + return ""; + } + set prop1(s: string | number) {} +>prop1 : Symbol(Two.prop1, Decl(divergentAccessorsTypes8.ts, 40, 11), Decl(divergentAccessorsTypes8.ts, 43, 3)) +>s : Symbol(s, Decl(divergentAccessorsTypes8.ts, 44, 12)) + + get prop2(): string { +>prop2 : Symbol(Two.prop2, Decl(divergentAccessorsTypes8.ts, 44, 34), Decl(divergentAccessorsTypes8.ts, 48, 3)) + + return ""; + } + set prop2(s: string) {} +>prop2 : Symbol(Two.prop2, Decl(divergentAccessorsTypes8.ts, 44, 34), Decl(divergentAccessorsTypes8.ts, 48, 3)) +>s : Symbol(s, Decl(divergentAccessorsTypes8.ts, 49, 12)) + + get prop3(): string { +>prop3 : Symbol(Two.prop3, Decl(divergentAccessorsTypes8.ts, 49, 25), Decl(divergentAccessorsTypes8.ts, 53, 3)) + + return ""; + } + set prop3(s: string | boolean) {} +>prop3 : Symbol(Two.prop3, Decl(divergentAccessorsTypes8.ts, 49, 25), Decl(divergentAccessorsTypes8.ts, 53, 3)) +>s : Symbol(s, Decl(divergentAccessorsTypes8.ts, 54, 12)) + + get prop4(): string { +>prop4 : Symbol(Two.prop4, Decl(divergentAccessorsTypes8.ts, 54, 35), Decl(divergentAccessorsTypes8.ts, 58, 3)) + + return ""; + } + set prop4(s: string | boolean) {} +>prop4 : Symbol(Two.prop4, Decl(divergentAccessorsTypes8.ts, 54, 35), Decl(divergentAccessorsTypes8.ts, 58, 3)) +>s : Symbol(s, Decl(divergentAccessorsTypes8.ts, 59, 12)) +} + +declare const u1: One | Two; +>u1 : Symbol(u1, Decl(divergentAccessorsTypes8.ts, 62, 13)) +>One : Symbol(One, Decl(divergentAccessorsTypes8.ts, 19, 33)) +>Two : Symbol(Two, Decl(divergentAccessorsTypes8.ts, 38, 1)) + +u1['prop1'] = 42; +>u1 : Symbol(u1, Decl(divergentAccessorsTypes8.ts, 62, 13)) +>'prop1' : Symbol(prop1, Decl(divergentAccessorsTypes8.ts, 21, 11), Decl(divergentAccessorsTypes8.ts, 24, 3), Decl(divergentAccessorsTypes8.ts, 40, 11), Decl(divergentAccessorsTypes8.ts, 43, 3)) + +u1['prop1'] = "hello"; +>u1 : Symbol(u1, Decl(divergentAccessorsTypes8.ts, 62, 13)) +>'prop1' : Symbol(prop1, Decl(divergentAccessorsTypes8.ts, 21, 11), Decl(divergentAccessorsTypes8.ts, 24, 3), Decl(divergentAccessorsTypes8.ts, 40, 11), Decl(divergentAccessorsTypes8.ts, 43, 3)) + +u1['prop2'] = 42; +>u1 : Symbol(u1, Decl(divergentAccessorsTypes8.ts, 62, 13)) +>'prop2' : Symbol(prop2, Decl(divergentAccessorsTypes8.ts, 25, 34), Decl(divergentAccessorsTypes8.ts, 29, 3), Decl(divergentAccessorsTypes8.ts, 44, 34), Decl(divergentAccessorsTypes8.ts, 48, 3)) + +u1['prop2'] = "hello"; +>u1 : Symbol(u1, Decl(divergentAccessorsTypes8.ts, 62, 13)) +>'prop2' : Symbol(prop2, Decl(divergentAccessorsTypes8.ts, 25, 34), Decl(divergentAccessorsTypes8.ts, 29, 3), Decl(divergentAccessorsTypes8.ts, 44, 34), Decl(divergentAccessorsTypes8.ts, 48, 3)) + +u1['prop3'] = 42; +>u1 : Symbol(u1, Decl(divergentAccessorsTypes8.ts, 62, 13)) +>'prop3' : Symbol(prop3, Decl(divergentAccessorsTypes8.ts, 30, 34), Decl(divergentAccessorsTypes8.ts, 49, 25), Decl(divergentAccessorsTypes8.ts, 53, 3)) + +u1['prop3'] = "hello"; +>u1 : Symbol(u1, Decl(divergentAccessorsTypes8.ts, 62, 13)) +>'prop3' : Symbol(prop3, Decl(divergentAccessorsTypes8.ts, 30, 34), Decl(divergentAccessorsTypes8.ts, 49, 25), Decl(divergentAccessorsTypes8.ts, 53, 3)) + +u1['prop3'] = true; +>u1 : Symbol(u1, Decl(divergentAccessorsTypes8.ts, 62, 13)) +>'prop3' : Symbol(prop3, Decl(divergentAccessorsTypes8.ts, 30, 34), Decl(divergentAccessorsTypes8.ts, 49, 25), Decl(divergentAccessorsTypes8.ts, 53, 3)) + +u1['prop4'] = 42; +>u1 : Symbol(u1, Decl(divergentAccessorsTypes8.ts, 62, 13)) +>'prop4' : Symbol(prop4, Decl(divergentAccessorsTypes8.ts, 32, 21), Decl(divergentAccessorsTypes8.ts, 36, 3), Decl(divergentAccessorsTypes8.ts, 54, 35), Decl(divergentAccessorsTypes8.ts, 58, 3)) + +u1['prop4'] = "hello"; +>u1 : Symbol(u1, Decl(divergentAccessorsTypes8.ts, 62, 13)) +>'prop4' : Symbol(prop4, Decl(divergentAccessorsTypes8.ts, 32, 21), Decl(divergentAccessorsTypes8.ts, 36, 3), Decl(divergentAccessorsTypes8.ts, 54, 35), Decl(divergentAccessorsTypes8.ts, 58, 3)) + +u1['prop4'] = true; +>u1 : Symbol(u1, Decl(divergentAccessorsTypes8.ts, 62, 13)) +>'prop4' : Symbol(prop4, Decl(divergentAccessorsTypes8.ts, 32, 21), Decl(divergentAccessorsTypes8.ts, 36, 3), Decl(divergentAccessorsTypes8.ts, 54, 35), Decl(divergentAccessorsTypes8.ts, 58, 3)) + +declare const i: One & Two; +>i : Symbol(i, Decl(divergentAccessorsTypes8.ts, 78, 13)) +>One : Symbol(One, Decl(divergentAccessorsTypes8.ts, 19, 33)) +>Two : Symbol(Two, Decl(divergentAccessorsTypes8.ts, 38, 1)) + +const iv1 = i['prop1']; +>iv1 : Symbol(iv1, Decl(divergentAccessorsTypes8.ts, 80, 5)) +>i : Symbol(i, Decl(divergentAccessorsTypes8.ts, 78, 13)) +>'prop1' : Symbol(prop1, Decl(divergentAccessorsTypes8.ts, 21, 11), Decl(divergentAccessorsTypes8.ts, 24, 3), Decl(divergentAccessorsTypes8.ts, 40, 11), Decl(divergentAccessorsTypes8.ts, 43, 3)) + +i['prop1'] = 42; +>i : Symbol(i, Decl(divergentAccessorsTypes8.ts, 78, 13)) +>'prop1' : Symbol(prop1, Decl(divergentAccessorsTypes8.ts, 21, 11), Decl(divergentAccessorsTypes8.ts, 24, 3), Decl(divergentAccessorsTypes8.ts, 40, 11), Decl(divergentAccessorsTypes8.ts, 43, 3)) + +i['prop1'] = "hello"; +>i : Symbol(i, Decl(divergentAccessorsTypes8.ts, 78, 13)) +>'prop1' : Symbol(prop1, Decl(divergentAccessorsTypes8.ts, 21, 11), Decl(divergentAccessorsTypes8.ts, 24, 3), Decl(divergentAccessorsTypes8.ts, 40, 11), Decl(divergentAccessorsTypes8.ts, 43, 3)) + +const iv2 = i['prop2']; +>iv2 : Symbol(iv2, Decl(divergentAccessorsTypes8.ts, 84, 5)) +>i : Symbol(i, Decl(divergentAccessorsTypes8.ts, 78, 13)) +>'prop2' : Symbol(prop2, Decl(divergentAccessorsTypes8.ts, 25, 34), Decl(divergentAccessorsTypes8.ts, 29, 3), Decl(divergentAccessorsTypes8.ts, 44, 34), Decl(divergentAccessorsTypes8.ts, 48, 3)) + +i['prop2'] = 42; +>i : Symbol(i, Decl(divergentAccessorsTypes8.ts, 78, 13)) +>'prop2' : Symbol(prop2, Decl(divergentAccessorsTypes8.ts, 25, 34), Decl(divergentAccessorsTypes8.ts, 29, 3), Decl(divergentAccessorsTypes8.ts, 44, 34), Decl(divergentAccessorsTypes8.ts, 48, 3)) + +i['prop2'] = "hello"; +>i : Symbol(i, Decl(divergentAccessorsTypes8.ts, 78, 13)) +>'prop2' : Symbol(prop2, Decl(divergentAccessorsTypes8.ts, 25, 34), Decl(divergentAccessorsTypes8.ts, 29, 3), Decl(divergentAccessorsTypes8.ts, 44, 34), Decl(divergentAccessorsTypes8.ts, 48, 3)) + +class Three { +>Three : Symbol(Three, Decl(divergentAccessorsTypes8.ts, 86, 21)) + + get prop1(): string { +>prop1 : Symbol(Three.prop1, Decl(divergentAccessorsTypes8.ts, 88, 13), Decl(divergentAccessorsTypes8.ts, 91, 3)) + + return ""; + } + set prop1(s: string | number) {} +>prop1 : Symbol(Three.prop1, Decl(divergentAccessorsTypes8.ts, 88, 13), Decl(divergentAccessorsTypes8.ts, 91, 3)) +>s : Symbol(s, Decl(divergentAccessorsTypes8.ts, 92, 12)) + + prop2: number = 42; +>prop2 : Symbol(Three.prop2, Decl(divergentAccessorsTypes8.ts, 92, 34)) +} + +class Four { +>Four : Symbol(Four, Decl(divergentAccessorsTypes8.ts, 95, 1)) + + get prop1(): "hello" { +>prop1 : Symbol(Four.prop1, Decl(divergentAccessorsTypes8.ts, 97, 12), Decl(divergentAccessorsTypes8.ts, 100, 3)) + + return "hello"; + } + set prop1(s: "hello" | number) {} +>prop1 : Symbol(Four.prop1, Decl(divergentAccessorsTypes8.ts, 97, 12), Decl(divergentAccessorsTypes8.ts, 100, 3)) +>s : Symbol(s, Decl(divergentAccessorsTypes8.ts, 101, 12)) + + get prop2(): string { +>prop2 : Symbol(Four.prop2, Decl(divergentAccessorsTypes8.ts, 101, 35), Decl(divergentAccessorsTypes8.ts, 105, 3)) + + return ""; + } + set prop2(s: string | 42) {} +>prop2 : Symbol(Four.prop2, Decl(divergentAccessorsTypes8.ts, 101, 35), Decl(divergentAccessorsTypes8.ts, 105, 3)) +>s : Symbol(s, Decl(divergentAccessorsTypes8.ts, 106, 12)) +} + +class Five { +>Five : Symbol(Five, Decl(divergentAccessorsTypes8.ts, 107, 1)) + + get prop1(): "hello" { +>prop1 : Symbol(Five.prop1, Decl(divergentAccessorsTypes8.ts, 109, 12), Decl(divergentAccessorsTypes8.ts, 112, 3)) + + return "hello"; + } + set prop1(s: "hello" | boolean) {} +>prop1 : Symbol(Five.prop1, Decl(divergentAccessorsTypes8.ts, 109, 12), Decl(divergentAccessorsTypes8.ts, 112, 3)) +>s : Symbol(s, Decl(divergentAccessorsTypes8.ts, 113, 12)) + + get prop2(): string { +>prop2 : Symbol(Five.prop2, Decl(divergentAccessorsTypes8.ts, 113, 36), Decl(divergentAccessorsTypes8.ts, 117, 3)) + + return ""; + } + set prop2(s: string | number | boolean) {} +>prop2 : Symbol(Five.prop2, Decl(divergentAccessorsTypes8.ts, 113, 36), Decl(divergentAccessorsTypes8.ts, 117, 3)) +>s : Symbol(s, Decl(divergentAccessorsTypes8.ts, 118, 12)) +} + +declare const i2: Three & Four & Five; +>i2 : Symbol(i2, Decl(divergentAccessorsTypes8.ts, 121, 13)) +>Three : Symbol(Three, Decl(divergentAccessorsTypes8.ts, 86, 21)) +>Four : Symbol(Four, Decl(divergentAccessorsTypes8.ts, 95, 1)) +>Five : Symbol(Five, Decl(divergentAccessorsTypes8.ts, 107, 1)) + +i2['prop1'] = 42; +>i2 : Symbol(i2, Decl(divergentAccessorsTypes8.ts, 121, 13)) +>'prop1' : Symbol(prop1, Decl(divergentAccessorsTypes8.ts, 88, 13), Decl(divergentAccessorsTypes8.ts, 91, 3), Decl(divergentAccessorsTypes8.ts, 97, 12), Decl(divergentAccessorsTypes8.ts, 100, 3), Decl(divergentAccessorsTypes8.ts, 109, 12) ... and 1 more) + +i2['prop1'] = "hello"; +>i2 : Symbol(i2, Decl(divergentAccessorsTypes8.ts, 121, 13)) +>'prop1' : Symbol(prop1, Decl(divergentAccessorsTypes8.ts, 88, 13), Decl(divergentAccessorsTypes8.ts, 91, 3), Decl(divergentAccessorsTypes8.ts, 97, 12), Decl(divergentAccessorsTypes8.ts, 100, 3), Decl(divergentAccessorsTypes8.ts, 109, 12) ... and 1 more) + +i2['prop2'] = 42; +>i2 : Symbol(i2, Decl(divergentAccessorsTypes8.ts, 121, 13)) +>'prop2' : Symbol(prop2, Decl(divergentAccessorsTypes8.ts, 92, 34), Decl(divergentAccessorsTypes8.ts, 101, 35), Decl(divergentAccessorsTypes8.ts, 105, 3), Decl(divergentAccessorsTypes8.ts, 113, 36), Decl(divergentAccessorsTypes8.ts, 117, 3)) + +i2['prop2'] = "hello"; +>i2 : Symbol(i2, Decl(divergentAccessorsTypes8.ts, 121, 13)) +>'prop2' : Symbol(prop2, Decl(divergentAccessorsTypes8.ts, 92, 34), Decl(divergentAccessorsTypes8.ts, 101, 35), Decl(divergentAccessorsTypes8.ts, 105, 3), Decl(divergentAccessorsTypes8.ts, 113, 36), Decl(divergentAccessorsTypes8.ts, 117, 3)) + +class Six { +>Six : Symbol(Six, Decl(divergentAccessorsTypes8.ts, 127, 22)) + + get prop1(): boolean | number { +>prop1 : Symbol(Six.prop1, Decl(divergentAccessorsTypes8.ts, 129, 11), Decl(divergentAccessorsTypes8.ts, 132, 3)) + + return 42; + } + set prop1(s: boolean | string) {} +>prop1 : Symbol(Six.prop1, Decl(divergentAccessorsTypes8.ts, 129, 11), Decl(divergentAccessorsTypes8.ts, 132, 3)) +>s : Symbol(s, Decl(divergentAccessorsTypes8.ts, 133, 12)) + + get prop2(): bigint | number { +>prop2 : Symbol(Six.prop2, Decl(divergentAccessorsTypes8.ts, 133, 35), Decl(divergentAccessorsTypes8.ts, 137, 3)) + + return 10; + } + set prop2(s: boolean | null) {} +>prop2 : Symbol(Six.prop2, Decl(divergentAccessorsTypes8.ts, 133, 35), Decl(divergentAccessorsTypes8.ts, 137, 3)) +>s : Symbol(s, Decl(divergentAccessorsTypes8.ts, 138, 12)) +} + +declare const s1: Six +>s1 : Symbol(s1, Decl(divergentAccessorsTypes8.ts, 141, 13)) +>Six : Symbol(Six, Decl(divergentAccessorsTypes8.ts, 127, 22)) + +declare const k1: 'prop1' | 'prop2' +>k1 : Symbol(k1, Decl(divergentAccessorsTypes8.ts, 142, 13)) + +const sv1 = s1[k1] +>sv1 : Symbol(sv1, Decl(divergentAccessorsTypes8.ts, 144, 5)) +>s1 : Symbol(s1, Decl(divergentAccessorsTypes8.ts, 141, 13)) +>k1 : Symbol(k1, Decl(divergentAccessorsTypes8.ts, 142, 13)) + +s1[k1] = 42 +>s1 : Symbol(s1, Decl(divergentAccessorsTypes8.ts, 141, 13)) +>k1 : Symbol(k1, Decl(divergentAccessorsTypes8.ts, 142, 13)) + +s1[k1] = true +>s1 : Symbol(s1, Decl(divergentAccessorsTypes8.ts, 141, 13)) +>k1 : Symbol(k1, Decl(divergentAccessorsTypes8.ts, 142, 13)) + +s1[k1] = '' +>s1 : Symbol(s1, Decl(divergentAccessorsTypes8.ts, 141, 13)) +>k1 : Symbol(k1, Decl(divergentAccessorsTypes8.ts, 142, 13)) + +s1[k1] = null +>s1 : Symbol(s1, Decl(divergentAccessorsTypes8.ts, 141, 13)) +>k1 : Symbol(k1, Decl(divergentAccessorsTypes8.ts, 142, 13)) + diff --git a/tests/baselines/reference/divergentAccessorsTypes8.types b/tests/baselines/reference/divergentAccessorsTypes8.types new file mode 100644 index 0000000000000..d847385f38ffd --- /dev/null +++ b/tests/baselines/reference/divergentAccessorsTypes8.types @@ -0,0 +1,429 @@ +//// [tests/cases/compiler/divergentAccessorsTypes8.ts] //// + +=== divergentAccessorsTypes8.ts === +export {} + +interface Serializer { + set value(v: string | number | boolean); +>value : string +>v : string | number | boolean + + get value(): string; +>value : string +} +declare let box: Serializer; +>box : Serializer + +const v = box['value'] +>v : string +>box['value'] : string +>box : Serializer +>'value' : "value" + +box['value'] = true; +>box['value'] = true : true +>box['value'] : string | number | boolean +>box : Serializer +>'value' : "value" +>true : true + +box['value'] = 42; +>box['value'] = 42 : 42 +>box['value'] : string | number | boolean +>box : Serializer +>'value' : "value" +>42 : 42 + +box['value'] = "hello"; +>box['value'] = "hello" : "hello" +>box['value'] : string | number | boolean +>box : Serializer +>'value' : "value" +>"hello" : "hello" + +interface Element { + get style(): CSSStyleDeclaration; +>style : CSSStyleDeclaration + + set style(cssText: string); +>style : CSSStyleDeclaration +>cssText : string +} + +declare const element: Element; +>element : Element + +element['style'] = "color: red"; +>element['style'] = "color: red" : "color: red" +>element['style'] : string +>element : Element +>'style' : "style" +>"color: red" : "color: red" + +element['style'] = element.style; +>element['style'] = element.style : CSSStyleDeclaration +>element['style'] : string +>element : Element +>'style' : "style" +>element.style : CSSStyleDeclaration +>element : Element +>style : CSSStyleDeclaration + +class One { +>One : One + + get prop1(): string { +>prop1 : string + + return ""; +>"" : "" + } + set prop1(s: string | number) {} +>prop1 : string +>s : string | number + + get prop2(): string { +>prop2 : string + + return ""; +>"" : "" + } + set prop2(s: string | number) {} +>prop2 : string +>s : string | number + + prop3: number = 42; +>prop3 : number +>42 : 42 + + get prop4(): string { +>prop4 : string + + return ""; +>"" : "" + } + set prop4(s: string | number) {} +>prop4 : string +>s : string | number +} + +class Two { +>Two : Two + + get prop1(): string { +>prop1 : string + + return ""; +>"" : "" + } + set prop1(s: string | number) {} +>prop1 : string +>s : string | number + + get prop2(): string { +>prop2 : string + + return ""; +>"" : "" + } + set prop2(s: string) {} +>prop2 : string +>s : string + + get prop3(): string { +>prop3 : string + + return ""; +>"" : "" + } + set prop3(s: string | boolean) {} +>prop3 : string +>s : string | boolean + + get prop4(): string { +>prop4 : string + + return ""; +>"" : "" + } + set prop4(s: string | boolean) {} +>prop4 : string +>s : string | boolean +} + +declare const u1: One | Two; +>u1 : One | Two + +u1['prop1'] = 42; +>u1['prop1'] = 42 : 42 +>u1['prop1'] : string | number +>u1 : One | Two +>'prop1' : "prop1" +>42 : 42 + +u1['prop1'] = "hello"; +>u1['prop1'] = "hello" : "hello" +>u1['prop1'] : string | number +>u1 : One | Two +>'prop1' : "prop1" +>"hello" : "hello" + +u1['prop2'] = 42; +>u1['prop2'] = 42 : 42 +>u1['prop2'] : string | number +>u1 : One | Two +>'prop2' : "prop2" +>42 : 42 + +u1['prop2'] = "hello"; +>u1['prop2'] = "hello" : "hello" +>u1['prop2'] : string | number +>u1 : One | Two +>'prop2' : "prop2" +>"hello" : "hello" + +u1['prop3'] = 42; +>u1['prop3'] = 42 : 42 +>u1['prop3'] : string | number | boolean +>u1 : One | Two +>'prop3' : "prop3" +>42 : 42 + +u1['prop3'] = "hello"; +>u1['prop3'] = "hello" : "hello" +>u1['prop3'] : string | number | boolean +>u1 : One | Two +>'prop3' : "prop3" +>"hello" : "hello" + +u1['prop3'] = true; +>u1['prop3'] = true : true +>u1['prop3'] : string | number | boolean +>u1 : One | Two +>'prop3' : "prop3" +>true : true + +u1['prop4'] = 42; +>u1['prop4'] = 42 : 42 +>u1['prop4'] : string | number | boolean +>u1 : One | Two +>'prop4' : "prop4" +>42 : 42 + +u1['prop4'] = "hello"; +>u1['prop4'] = "hello" : "hello" +>u1['prop4'] : string | number | boolean +>u1 : One | Two +>'prop4' : "prop4" +>"hello" : "hello" + +u1['prop4'] = true; +>u1['prop4'] = true : true +>u1['prop4'] : string | number | boolean +>u1 : One | Two +>'prop4' : "prop4" +>true : true + +declare const i: One & Two; +>i : One & Two + +const iv1 = i['prop1']; +>iv1 : string +>i['prop1'] : string +>i : One & Two +>'prop1' : "prop1" + +i['prop1'] = 42; +>i['prop1'] = 42 : 42 +>i['prop1'] : string | number +>i : One & Two +>'prop1' : "prop1" +>42 : 42 + +i['prop1'] = "hello"; +>i['prop1'] = "hello" : "hello" +>i['prop1'] : string | number +>i : One & Two +>'prop1' : "prop1" +>"hello" : "hello" + +const iv2 = i['prop2']; +>iv2 : string +>i['prop2'] : string +>i : One & Two +>'prop2' : "prop2" + +i['prop2'] = 42; +>i['prop2'] = 42 : 42 +>i['prop2'] : string +>i : One & Two +>'prop2' : "prop2" +>42 : 42 + +i['prop2'] = "hello"; +>i['prop2'] = "hello" : "hello" +>i['prop2'] : string +>i : One & Two +>'prop2' : "prop2" +>"hello" : "hello" + +class Three { +>Three : Three + + get prop1(): string { +>prop1 : string + + return ""; +>"" : "" + } + set prop1(s: string | number) {} +>prop1 : string +>s : string | number + + prop2: number = 42; +>prop2 : number +>42 : 42 +} + +class Four { +>Four : Four + + get prop1(): "hello" { +>prop1 : "hello" + + return "hello"; +>"hello" : "hello" + } + set prop1(s: "hello" | number) {} +>prop1 : "hello" +>s : number | "hello" + + get prop2(): string { +>prop2 : string + + return ""; +>"" : "" + } + set prop2(s: string | 42) {} +>prop2 : string +>s : string | 42 +} + +class Five { +>Five : Five + + get prop1(): "hello" { +>prop1 : "hello" + + return "hello"; +>"hello" : "hello" + } + set prop1(s: "hello" | boolean) {} +>prop1 : "hello" +>s : boolean | "hello" + + get prop2(): string { +>prop2 : string + + return ""; +>"" : "" + } + set prop2(s: string | number | boolean) {} +>prop2 : string +>s : string | number | boolean +} + +declare const i2: Three & Four & Five; +>i2 : Three & Four & Five + +i2['prop1'] = 42; +>i2['prop1'] = 42 : 42 +>i2['prop1'] : "hello" +>i2 : Three & Four & Five +>'prop1' : "prop1" +>42 : 42 + +i2['prop1'] = "hello"; +>i2['prop1'] = "hello" : "hello" +>i2['prop1'] : "hello" +>i2 : Three & Four & Five +>'prop1' : "prop1" +>"hello" : "hello" + +i2['prop2'] = 42; +>i2['prop2'] = 42 : 42 +>i2['prop2'] : 42 +>i2 : Three & Four & Five +>'prop2' : "prop2" +>42 : 42 + +i2['prop2'] = "hello"; +>i2['prop2'] = "hello" : "hello" +>i2['prop2'] : 42 +>i2 : Three & Four & Five +>'prop2' : "prop2" +>"hello" : "hello" + +class Six { +>Six : Six + + get prop1(): boolean | number { +>prop1 : number | boolean + + return 42; +>42 : 42 + } + set prop1(s: boolean | string) {} +>prop1 : number | boolean +>s : string | boolean + + get prop2(): bigint | number { +>prop2 : number | bigint + + return 10; +>10 : 10 + } + set prop2(s: boolean | null) {} +>prop2 : number | bigint +>s : boolean | null +} + +declare const s1: Six +>s1 : Six + +declare const k1: 'prop1' | 'prop2' +>k1 : "prop1" | "prop2" + +const sv1 = s1[k1] +>sv1 : number | bigint | boolean +>s1[k1] : number | bigint | boolean +>s1 : Six +>k1 : "prop1" | "prop2" + +s1[k1] = 42 +>s1[k1] = 42 : 42 +>s1[k1] : boolean +>s1 : Six +>k1 : "prop1" | "prop2" +>42 : 42 + +s1[k1] = true +>s1[k1] = true : true +>s1[k1] : boolean +>s1 : Six +>k1 : "prop1" | "prop2" +>true : true + +s1[k1] = '' +>s1[k1] = '' : "" +>s1[k1] : boolean +>s1 : Six +>k1 : "prop1" | "prop2" +>'' : "" + +s1[k1] = null +>s1[k1] = null : null +>s1[k1] : boolean +>s1 : Six +>k1 : "prop1" | "prop2" + diff --git a/tests/cases/compiler/divergentAccessorsTypes7.ts b/tests/cases/compiler/divergentAccessorsTypes7.ts index 830820221051f..cecf590b5613f 100644 --- a/tests/cases/compiler/divergentAccessorsTypes7.ts +++ b/tests/cases/compiler/divergentAccessorsTypes7.ts @@ -6,12 +6,12 @@ class Test { get value(): string { return null!; } - + // -- Replacing the getter such that the getter/setter types match, removes the error: // get value(): string | ((item: S) => string) { // return null!; // } - + // -- Or, replacing the setter such that a concrete type is used, removes the error: // set value(value: string | ((item: { property: string }) => string)) {} } @@ -21,3 +21,4 @@ const a = new Test<{ }>(); a.value = (item) => item.property +a['value'] = (item) => item.property diff --git a/tests/cases/compiler/divergentAccessorsTypes8.ts b/tests/cases/compiler/divergentAccessorsTypes8.ts new file mode 100644 index 0000000000000..0ea9349059593 --- /dev/null +++ b/tests/cases/compiler/divergentAccessorsTypes8.ts @@ -0,0 +1,153 @@ +// @strict: true +// @lib: esnext, dom +// @noEmit: true + +export {} + +interface Serializer { + set value(v: string | number | boolean); + get value(): string; +} +declare let box: Serializer; +const v = box['value'] +box['value'] = true; +box['value'] = 42; +box['value'] = "hello"; + +interface Element { + get style(): CSSStyleDeclaration; + set style(cssText: string); +} + +declare const element: Element; +element['style'] = "color: red"; +element['style'] = element.style; + +class One { + get prop1(): string { + return ""; + } + set prop1(s: string | number) {} + + get prop2(): string { + return ""; + } + set prop2(s: string | number) {} + + prop3: number = 42; + + get prop4(): string { + return ""; + } + set prop4(s: string | number) {} +} + +class Two { + get prop1(): string { + return ""; + } + set prop1(s: string | number) {} + + get prop2(): string { + return ""; + } + set prop2(s: string) {} + + get prop3(): string { + return ""; + } + set prop3(s: string | boolean) {} + + get prop4(): string { + return ""; + } + set prop4(s: string | boolean) {} +} + +declare const u1: One | Two; + +u1['prop1'] = 42; +u1['prop1'] = "hello"; + +u1['prop2'] = 42; +u1['prop2'] = "hello"; + +u1['prop3'] = 42; +u1['prop3'] = "hello"; +u1['prop3'] = true; + +u1['prop4'] = 42; +u1['prop4'] = "hello"; +u1['prop4'] = true; + +declare const i: One & Two; + +const iv1 = i['prop1']; +i['prop1'] = 42; +i['prop1'] = "hello"; + +const iv2 = i['prop2']; +i['prop2'] = 42; +i['prop2'] = "hello"; + +class Three { + get prop1(): string { + return ""; + } + set prop1(s: string | number) {} + + prop2: number = 42; +} + +class Four { + get prop1(): "hello" { + return "hello"; + } + set prop1(s: "hello" | number) {} + + get prop2(): string { + return ""; + } + set prop2(s: string | 42) {} +} + +class Five { + get prop1(): "hello" { + return "hello"; + } + set prop1(s: "hello" | boolean) {} + + get prop2(): string { + return ""; + } + set prop2(s: string | number | boolean) {} +} + +declare const i2: Three & Four & Five; + +i2['prop1'] = 42; +i2['prop1'] = "hello"; + +i2['prop2'] = 42; +i2['prop2'] = "hello"; + +class Six { + get prop1(): boolean | number { + return 42; + } + set prop1(s: boolean | string) {} + + get prop2(): bigint | number { + return 10; + } + set prop2(s: boolean | null) {} +} + +declare const s1: Six +declare const k1: 'prop1' | 'prop2' + +const sv1 = s1[k1] +s1[k1] = 42 +s1[k1] = true +s1[k1] = '' +s1[k1] = null diff --git a/tests/cases/fourslash/quickInfoOnElementAccessInWriteLocation1.ts b/tests/cases/fourslash/quickInfoOnElementAccessInWriteLocation1.ts new file mode 100644 index 0000000000000..c08e6ef6caf34 --- /dev/null +++ b/tests/cases/fourslash/quickInfoOnElementAccessInWriteLocation1.ts @@ -0,0 +1,8 @@ +/// + +// @strict: true +// @exactOptionalPropertyTypes: true +//// declare const xx: { prop?: number }; +//// xx['prop'/*1*/] = 1; + +verify.quickInfoAt('1', '(property) prop?: number'); diff --git a/tests/cases/fourslash/quickInfoOnElementAccessInWriteLocation2.ts b/tests/cases/fourslash/quickInfoOnElementAccessInWriteLocation2.ts new file mode 100644 index 0000000000000..14f60eea0213c --- /dev/null +++ b/tests/cases/fourslash/quickInfoOnElementAccessInWriteLocation2.ts @@ -0,0 +1,8 @@ +/// + +// @strict: true +// @exactOptionalPropertyTypes: true +//// declare const xx: { prop?: number }; +//// xx['prop'/*1*/] += 1; + +verify.quickInfoAt('1', '(property) prop?: number'); diff --git a/tests/cases/fourslash/quickInfoOnElementAccessInWriteLocation3.ts b/tests/cases/fourslash/quickInfoOnElementAccessInWriteLocation3.ts new file mode 100644 index 0000000000000..108fd22182f34 --- /dev/null +++ b/tests/cases/fourslash/quickInfoOnElementAccessInWriteLocation3.ts @@ -0,0 +1,8 @@ +/// + +// @strict: true +// @exactOptionalPropertyTypes: true +//// declare const xx: { prop?: number }; +//// xx['prop'/*1*/] ??= 1; + +verify.quickInfoAt('1', '(property) prop?: number'); diff --git a/tests/cases/fourslash/quickInfoOnElementAccessInWriteLocation4.ts b/tests/cases/fourslash/quickInfoOnElementAccessInWriteLocation4.ts new file mode 100644 index 0000000000000..98e0bf5081c6d --- /dev/null +++ b/tests/cases/fourslash/quickInfoOnElementAccessInWriteLocation4.ts @@ -0,0 +1,11 @@ +/// + +// @strict: true +//// interface Serializer { +//// set value(v: string | number | boolean); +//// get value(): string; +//// } +//// declare let box: Serializer; +//// box['value'/*1*/] = true; + +verify.quickInfoAt('1', '(property) Serializer.value: string | number | boolean'); diff --git a/tests/cases/fourslash/quickInfoOnElementAccessInWriteLocation5.ts b/tests/cases/fourslash/quickInfoOnElementAccessInWriteLocation5.ts new file mode 100644 index 0000000000000..8348bf6a454c5 --- /dev/null +++ b/tests/cases/fourslash/quickInfoOnElementAccessInWriteLocation5.ts @@ -0,0 +1,11 @@ +/// + +// @strict: true +//// interface Serializer { +//// set value(v: string | number); +//// get value(): string; +//// } +//// declare let box: Serializer; +//// box['value'/*1*/] += 10; + +verify.quickInfoAt('1', '(property) Serializer.value: string | number');