Skip to content

Commit 5586727

Browse files
authored
Allow getter and setter types to be unrelated (#53417)
1 parent 7bde5ef commit 5586727

22 files changed

+344
-81
lines changed

src/compiler/checker.ts

-6
Original file line numberDiff line numberDiff line change
@@ -38507,12 +38507,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3850738507
error(getter.name, Diagnostics.A_get_accessor_must_be_at_least_as_accessible_as_the_setter);
3850838508
error(setter.name, Diagnostics.A_get_accessor_must_be_at_least_as_accessible_as_the_setter);
3850938509
}
38510-
38511-
const getterType = getAnnotatedAccessorType(getter);
38512-
const setterType = getAnnotatedAccessorType(setter);
38513-
if (getterType && setterType) {
38514-
checkTypeAssignableTo(getterType, setterType, getter, Diagnostics.The_return_type_of_a_get_accessor_must_be_assignable_to_its_set_accessor_type);
38515-
}
3851638510
}
3851738511
}
3851838512
const returnType = getTypeOfAccessors(getSymbolOfDeclaration(node));

src/compiler/diagnosticMessages.json

-4
Original file line numberDiff line numberDiff line change
@@ -1972,10 +1972,6 @@
19721972
"category": "Error",
19731973
"code": 2379
19741974
},
1975-
"The return type of a 'get' accessor must be assignable to its 'set' accessor type": {
1976-
"category": "Error",
1977-
"code": 2380
1978-
},
19791975
"Overload signatures must all be exported or non-exported.": {
19801976
"category": "Error",
19811977
"code": 2383

tests/baselines/reference/abstractPropertyNegative.errors.txt

+2-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
tests/cases/compiler/abstractPropertyNegative.ts(10,18): error TS2380: The return type of a 'get' accessor must be assignable to its 'set' accessor type
21
tests/cases/compiler/abstractPropertyNegative.ts(13,7): error TS18052: Non-abstract class 'C' does not implement all abstract members of 'B'
32
tests/cases/compiler/abstractPropertyNegative.ts(15,5): error TS1253: Abstract properties can only appear within an abstract class.
43
tests/cases/compiler/abstractPropertyNegative.ts(16,37): error TS1005: '{' expected.
@@ -15,7 +14,7 @@ tests/cases/compiler/abstractPropertyNegative.ts(40,9): error TS2676: Accessors
1514
tests/cases/compiler/abstractPropertyNegative.ts(41,18): error TS2676: Accessors must both be abstract or non-abstract.
1615

1716

18-
==== tests/cases/compiler/abstractPropertyNegative.ts (12 errors) ====
17+
==== tests/cases/compiler/abstractPropertyNegative.ts (11 errors) ====
1918
interface A {
2019
prop: string;
2120
m(): string;
@@ -26,9 +25,7 @@ tests/cases/compiler/abstractPropertyNegative.ts(41,18): error TS2676: Accessors
2625
abstract get readonlyProp(): string;
2726
abstract m(): string;
2827
abstract get mismatch(): string;
29-
~~~~~~~~
30-
!!! error TS2380: The return type of a 'get' accessor must be assignable to its 'set' accessor type
31-
abstract set mismatch(val: number); // error, not same type
28+
abstract set mismatch(val: number);
3229
}
3330
class C extends B {
3431
~

tests/baselines/reference/abstractPropertyNegative.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ abstract class B implements A {
99
abstract get readonlyProp(): string;
1010
abstract m(): string;
1111
abstract get mismatch(): string;
12-
abstract set mismatch(val: number); // error, not same type
12+
abstract set mismatch(val: number);
1313
}
1414
class C extends B {
1515
readonly ro = "readonly please";

tests/baselines/reference/abstractPropertyNegative.symbols

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ abstract class B implements A {
2727
abstract get mismatch(): string;
2828
>mismatch : Symbol(B.mismatch, Decl(abstractPropertyNegative.ts, 8, 25), Decl(abstractPropertyNegative.ts, 9, 36))
2929

30-
abstract set mismatch(val: number); // error, not same type
30+
abstract set mismatch(val: number);
3131
>mismatch : Symbol(B.mismatch, Decl(abstractPropertyNegative.ts, 8, 25), Decl(abstractPropertyNegative.ts, 9, 36))
3232
>val : Symbol(val, Decl(abstractPropertyNegative.ts, 10, 26))
3333
}

tests/baselines/reference/abstractPropertyNegative.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ abstract class B implements A {
2424
abstract get mismatch(): string;
2525
>mismatch : string
2626

27-
abstract set mismatch(val: number); // error, not same type
27+
abstract set mismatch(val: number);
2828
>mismatch : string
2929
>val : number
3030
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
tests/cases/compiler/divergentAccessorsTypes6.ts(11,1): error TS2322: Type 'CSSStyleDeclaration' is not assignable to type 'string'.
2+
tests/cases/compiler/divergentAccessorsTypes6.ts(19,23): error TS2344: Type 'string' does not satisfy the constraint 'never'.
3+
tests/cases/compiler/divergentAccessorsTypes6.ts(23,23): error TS2344: Type 'string' does not satisfy the constraint 'never'.
4+
tests/cases/compiler/divergentAccessorsTypes6.ts(29,16): error TS2322: Type 'number' is not assignable to type 'string'.
5+
6+
7+
==== tests/cases/compiler/divergentAccessorsTypes6.ts (4 errors) ====
8+
export {};
9+
10+
interface Element {
11+
get style(): CSSStyleDeclaration;
12+
set style(cssText: string);
13+
}
14+
15+
declare const element: Element;
16+
element.style = "color: red";
17+
element.style.animationTimingFunction;
18+
element.style = element.style; // error
19+
~~~~~~~~~~~~~
20+
!!! error TS2322: Type 'CSSStyleDeclaration' is not assignable to type 'string'.
21+
22+
// Now that we don't check for getter/setter assignability, we should
23+
// ensure the setter annotation is actually checked even if it's never observed.
24+
25+
type Fail<T extends never> = T;
26+
interface I1 {
27+
get x(): number;
28+
set x(value: Fail<string>);
29+
~~~~~~
30+
!!! error TS2344: Type 'string' does not satisfy the constraint 'never'.
31+
}
32+
const o1 = {
33+
get x(): number { return 0; },
34+
set x(value: Fail<string>) {}
35+
~~~~~~
36+
!!! error TS2344: Type 'string' does not satisfy the constraint 'never'.
37+
}
38+
39+
// A setter annotation still implies the getter return type.
40+
41+
const o2 = {
42+
get p1() { return 0; }, // error - no annotation means type is implied from the setter annotation
43+
~~~~~~
44+
!!! error TS2322: Type 'number' is not assignable to type 'string'.
45+
set p1(value: string) {},
46+
47+
get p2(): number { return 0; }, // ok - explicit annotation
48+
set p2(value: string) {},
49+
};
50+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//// [divergentAccessorsTypes6.ts]
2+
export {};
3+
4+
interface Element {
5+
get style(): CSSStyleDeclaration;
6+
set style(cssText: string);
7+
}
8+
9+
declare const element: Element;
10+
element.style = "color: red";
11+
element.style.animationTimingFunction;
12+
element.style = element.style; // error
13+
14+
// Now that we don't check for getter/setter assignability, we should
15+
// ensure the setter annotation is actually checked even if it's never observed.
16+
17+
type Fail<T extends never> = T;
18+
interface I1 {
19+
get x(): number;
20+
set x(value: Fail<string>);
21+
}
22+
const o1 = {
23+
get x(): number { return 0; },
24+
set x(value: Fail<string>) {}
25+
}
26+
27+
// A setter annotation still implies the getter return type.
28+
29+
const o2 = {
30+
get p1() { return 0; }, // error - no annotation means type is implied from the setter annotation
31+
set p1(value: string) {},
32+
33+
get p2(): number { return 0; }, // ok - explicit annotation
34+
set p2(value: string) {},
35+
};
36+
37+
38+
//// [divergentAccessorsTypes6.js]
39+
"use strict";
40+
Object.defineProperty(exports, "__esModule", { value: true });
41+
element.style = "color: red";
42+
element.style.animationTimingFunction;
43+
element.style = element.style; // error
44+
var o1 = {
45+
get x() { return 0; },
46+
set x(value) { }
47+
};
48+
// A setter annotation still implies the getter return type.
49+
var o2 = {
50+
get p1() { return 0; },
51+
set p1(value) { },
52+
get p2() { return 0; },
53+
set p2(value) { },
54+
};
55+
56+
57+
//// [divergentAccessorsTypes6.d.ts]
58+
export {};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
=== tests/cases/compiler/divergentAccessorsTypes6.ts ===
2+
export {};
3+
4+
interface Element {
5+
>Element : Symbol(Element, Decl(divergentAccessorsTypes6.ts, 0, 10))
6+
7+
get style(): CSSStyleDeclaration;
8+
>style : Symbol(Element.style, Decl(divergentAccessorsTypes6.ts, 2, 19), Decl(divergentAccessorsTypes6.ts, 3, 37))
9+
>CSSStyleDeclaration : Symbol(CSSStyleDeclaration, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --))
10+
11+
set style(cssText: string);
12+
>style : Symbol(Element.style, Decl(divergentAccessorsTypes6.ts, 2, 19), Decl(divergentAccessorsTypes6.ts, 3, 37))
13+
>cssText : Symbol(cssText, Decl(divergentAccessorsTypes6.ts, 4, 14))
14+
}
15+
16+
declare const element: Element;
17+
>element : Symbol(element, Decl(divergentAccessorsTypes6.ts, 7, 13))
18+
>Element : Symbol(Element, Decl(divergentAccessorsTypes6.ts, 0, 10))
19+
20+
element.style = "color: red";
21+
>element.style : Symbol(Element.style, Decl(divergentAccessorsTypes6.ts, 2, 19), Decl(divergentAccessorsTypes6.ts, 3, 37))
22+
>element : Symbol(element, Decl(divergentAccessorsTypes6.ts, 7, 13))
23+
>style : Symbol(Element.style, Decl(divergentAccessorsTypes6.ts, 2, 19), Decl(divergentAccessorsTypes6.ts, 3, 37))
24+
25+
element.style.animationTimingFunction;
26+
>element.style.animationTimingFunction : Symbol(CSSStyleDeclaration.animationTimingFunction, Decl(lib.dom.d.ts, --, --))
27+
>element.style : Symbol(Element.style, Decl(divergentAccessorsTypes6.ts, 2, 19), Decl(divergentAccessorsTypes6.ts, 3, 37))
28+
>element : Symbol(element, Decl(divergentAccessorsTypes6.ts, 7, 13))
29+
>style : Symbol(Element.style, Decl(divergentAccessorsTypes6.ts, 2, 19), Decl(divergentAccessorsTypes6.ts, 3, 37))
30+
>animationTimingFunction : Symbol(CSSStyleDeclaration.animationTimingFunction, Decl(lib.dom.d.ts, --, --))
31+
32+
element.style = element.style; // error
33+
>element.style : Symbol(Element.style, Decl(divergentAccessorsTypes6.ts, 2, 19), Decl(divergentAccessorsTypes6.ts, 3, 37))
34+
>element : Symbol(element, Decl(divergentAccessorsTypes6.ts, 7, 13))
35+
>style : Symbol(Element.style, Decl(divergentAccessorsTypes6.ts, 2, 19), Decl(divergentAccessorsTypes6.ts, 3, 37))
36+
>element.style : Symbol(Element.style, Decl(divergentAccessorsTypes6.ts, 2, 19), Decl(divergentAccessorsTypes6.ts, 3, 37))
37+
>element : Symbol(element, Decl(divergentAccessorsTypes6.ts, 7, 13))
38+
>style : Symbol(Element.style, Decl(divergentAccessorsTypes6.ts, 2, 19), Decl(divergentAccessorsTypes6.ts, 3, 37))
39+
40+
// Now that we don't check for getter/setter assignability, we should
41+
// ensure the setter annotation is actually checked even if it's never observed.
42+
43+
type Fail<T extends never> = T;
44+
>Fail : Symbol(Fail, Decl(divergentAccessorsTypes6.ts, 10, 30))
45+
>T : Symbol(T, Decl(divergentAccessorsTypes6.ts, 15, 10))
46+
>T : Symbol(T, Decl(divergentAccessorsTypes6.ts, 15, 10))
47+
48+
interface I1 {
49+
>I1 : Symbol(I1, Decl(divergentAccessorsTypes6.ts, 15, 31))
50+
51+
get x(): number;
52+
>x : Symbol(I1.x, Decl(divergentAccessorsTypes6.ts, 16, 14), Decl(divergentAccessorsTypes6.ts, 17, 20))
53+
54+
set x(value: Fail<string>);
55+
>x : Symbol(I1.x, Decl(divergentAccessorsTypes6.ts, 16, 14), Decl(divergentAccessorsTypes6.ts, 17, 20))
56+
>value : Symbol(value, Decl(divergentAccessorsTypes6.ts, 18, 10))
57+
>Fail : Symbol(Fail, Decl(divergentAccessorsTypes6.ts, 10, 30))
58+
}
59+
const o1 = {
60+
>o1 : Symbol(o1, Decl(divergentAccessorsTypes6.ts, 20, 5))
61+
62+
get x(): number { return 0; },
63+
>x : Symbol(x, Decl(divergentAccessorsTypes6.ts, 20, 12), Decl(divergentAccessorsTypes6.ts, 21, 34))
64+
65+
set x(value: Fail<string>) {}
66+
>x : Symbol(x, Decl(divergentAccessorsTypes6.ts, 20, 12), Decl(divergentAccessorsTypes6.ts, 21, 34))
67+
>value : Symbol(value, Decl(divergentAccessorsTypes6.ts, 22, 10))
68+
>Fail : Symbol(Fail, Decl(divergentAccessorsTypes6.ts, 10, 30))
69+
}
70+
71+
// A setter annotation still implies the getter return type.
72+
73+
const o2 = {
74+
>o2 : Symbol(o2, Decl(divergentAccessorsTypes6.ts, 27, 5))
75+
76+
get p1() { return 0; }, // error - no annotation means type is implied from the setter annotation
77+
>p1 : Symbol(p1, Decl(divergentAccessorsTypes6.ts, 27, 12), Decl(divergentAccessorsTypes6.ts, 28, 27))
78+
79+
set p1(value: string) {},
80+
>p1 : Symbol(p1, Decl(divergentAccessorsTypes6.ts, 27, 12), Decl(divergentAccessorsTypes6.ts, 28, 27))
81+
>value : Symbol(value, Decl(divergentAccessorsTypes6.ts, 29, 11))
82+
83+
get p2(): number { return 0; }, // ok - explicit annotation
84+
>p2 : Symbol(p2, Decl(divergentAccessorsTypes6.ts, 29, 29), Decl(divergentAccessorsTypes6.ts, 31, 35))
85+
86+
set p2(value: string) {},
87+
>p2 : Symbol(p2, Decl(divergentAccessorsTypes6.ts, 29, 29), Decl(divergentAccessorsTypes6.ts, 31, 35))
88+
>value : Symbol(value, Decl(divergentAccessorsTypes6.ts, 32, 11))
89+
90+
};
91+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
=== tests/cases/compiler/divergentAccessorsTypes6.ts ===
2+
export {};
3+
4+
interface Element {
5+
get style(): CSSStyleDeclaration;
6+
>style : CSSStyleDeclaration
7+
8+
set style(cssText: string);
9+
>style : CSSStyleDeclaration
10+
>cssText : string
11+
}
12+
13+
declare const element: Element;
14+
>element : Element
15+
16+
element.style = "color: red";
17+
>element.style = "color: red" : "color: red"
18+
>element.style : string
19+
>element : Element
20+
>style : string
21+
>"color: red" : "color: red"
22+
23+
element.style.animationTimingFunction;
24+
>element.style.animationTimingFunction : string
25+
>element.style : CSSStyleDeclaration
26+
>element : Element
27+
>style : CSSStyleDeclaration
28+
>animationTimingFunction : string
29+
30+
element.style = element.style; // error
31+
>element.style = element.style : CSSStyleDeclaration
32+
>element.style : string
33+
>element : Element
34+
>style : string
35+
>element.style : CSSStyleDeclaration
36+
>element : Element
37+
>style : CSSStyleDeclaration
38+
39+
// Now that we don't check for getter/setter assignability, we should
40+
// ensure the setter annotation is actually checked even if it's never observed.
41+
42+
type Fail<T extends never> = T;
43+
>Fail : T
44+
45+
interface I1 {
46+
get x(): number;
47+
>x : number
48+
49+
set x(value: Fail<string>);
50+
>x : number
51+
>value : string
52+
}
53+
const o1 = {
54+
>o1 : { x: number; }
55+
>{ get x(): number { return 0; }, set x(value: Fail<string>) {}} : { x: number; }
56+
57+
get x(): number { return 0; },
58+
>x : number
59+
>0 : 0
60+
61+
set x(value: Fail<string>) {}
62+
>x : number
63+
>value : string
64+
}
65+
66+
// A setter annotation still implies the getter return type.
67+
68+
const o2 = {
69+
>o2 : { p1: string; p2: number; }
70+
>{ get p1() { return 0; }, // error - no annotation means type is implied from the setter annotation set p1(value: string) {}, get p2(): number { return 0; }, // ok - explicit annotation set p2(value: string) {},} : { p1: string; p2: number; }
71+
72+
get p1() { return 0; }, // error - no annotation means type is implied from the setter annotation
73+
>p1 : string
74+
>0 : 0
75+
76+
set p1(value: string) {},
77+
>p1 : string
78+
>value : string
79+
80+
get p2(): number { return 0; }, // ok - explicit annotation
81+
>p2 : number
82+
>0 : 0
83+
84+
set p2(value: string) {},
85+
>p2 : number
86+
>value : string
87+
88+
};
89+

tests/baselines/reference/getAndSetNotIdenticalType.errors.txt

-12
This file was deleted.

0 commit comments

Comments
 (0)