Skip to content

Commit 7191875

Browse files
authored
Use full isReadonlySymbol check rather than declaration flags (microsoft#48064)
* Use full `isReadonlySymbol` check rather than declaration flags * Limit subtype readonly consistency check to strict subtype relation * Update comment
1 parent 1abc47b commit 7191875

9 files changed

+133
-2
lines changed

src/compiler/checker.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -19747,9 +19747,10 @@ namespace ts {
1974719747
// This ensures the subtype relationship is ordered, and preventing declaration order
1974819748
// from deciding which type "wins" in union subtype reduction.
1974919749
// They're still assignable to one another, since `readonly` doesn't affect assignability.
19750+
// This is only applied during the strictSubtypeRelation -- currently used in subtype reduction
1975019751
if (
19751-
(relation === subtypeRelation || relation === strictSubtypeRelation) &&
19752-
!!(sourcePropFlags & ModifierFlags.Readonly) && !(targetPropFlags & ModifierFlags.Readonly)
19752+
relation === strictSubtypeRelation &&
19753+
isReadonlySymbol(sourceProp) && !isReadonlySymbol(targetProp)
1975319754
) {
1975419755
return Ternary.False;
1975519756
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//// [typeGuardNarrowByMutableUntypedField.ts]
2+
declare function hasOwnProperty<P extends PropertyKey>(target: {}, property: P): target is { [K in P]: unknown };
3+
declare const arrayLikeOrIterable: ArrayLike<any> | Iterable<any>;
4+
if (hasOwnProperty(arrayLikeOrIterable, 'length')) {
5+
let x: number = arrayLikeOrIterable.length;
6+
}
7+
8+
//// [typeGuardNarrowByMutableUntypedField.js]
9+
if (hasOwnProperty(arrayLikeOrIterable, 'length')) {
10+
var x = arrayLikeOrIterable.length;
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
=== tests/cases/compiler/typeGuardNarrowByMutableUntypedField.ts ===
2+
declare function hasOwnProperty<P extends PropertyKey>(target: {}, property: P): target is { [K in P]: unknown };
3+
>hasOwnProperty : Symbol(hasOwnProperty, Decl(typeGuardNarrowByMutableUntypedField.ts, 0, 0))
4+
>P : Symbol(P, Decl(typeGuardNarrowByMutableUntypedField.ts, 0, 32))
5+
>PropertyKey : Symbol(PropertyKey, Decl(lib.es5.d.ts, --, --))
6+
>target : Symbol(target, Decl(typeGuardNarrowByMutableUntypedField.ts, 0, 55))
7+
>property : Symbol(property, Decl(typeGuardNarrowByMutableUntypedField.ts, 0, 66))
8+
>P : Symbol(P, Decl(typeGuardNarrowByMutableUntypedField.ts, 0, 32))
9+
>target : Symbol(target, Decl(typeGuardNarrowByMutableUntypedField.ts, 0, 55))
10+
>K : Symbol(K, Decl(typeGuardNarrowByMutableUntypedField.ts, 0, 94))
11+
>P : Symbol(P, Decl(typeGuardNarrowByMutableUntypedField.ts, 0, 32))
12+
13+
declare const arrayLikeOrIterable: ArrayLike<any> | Iterable<any>;
14+
>arrayLikeOrIterable : Symbol(arrayLikeOrIterable, Decl(typeGuardNarrowByMutableUntypedField.ts, 1, 13))
15+
>ArrayLike : Symbol(ArrayLike, Decl(lib.es5.d.ts, --, --))
16+
>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --))
17+
18+
if (hasOwnProperty(arrayLikeOrIterable, 'length')) {
19+
>hasOwnProperty : Symbol(hasOwnProperty, Decl(typeGuardNarrowByMutableUntypedField.ts, 0, 0))
20+
>arrayLikeOrIterable : Symbol(arrayLikeOrIterable, Decl(typeGuardNarrowByMutableUntypedField.ts, 1, 13))
21+
22+
let x: number = arrayLikeOrIterable.length;
23+
>x : Symbol(x, Decl(typeGuardNarrowByMutableUntypedField.ts, 3, 7))
24+
>arrayLikeOrIterable.length : Symbol(ArrayLike.length, Decl(lib.es5.d.ts, --, --))
25+
>arrayLikeOrIterable : Symbol(arrayLikeOrIterable, Decl(typeGuardNarrowByMutableUntypedField.ts, 1, 13))
26+
>length : Symbol(ArrayLike.length, Decl(lib.es5.d.ts, --, --))
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
=== tests/cases/compiler/typeGuardNarrowByMutableUntypedField.ts ===
2+
declare function hasOwnProperty<P extends PropertyKey>(target: {}, property: P): target is { [K in P]: unknown };
3+
>hasOwnProperty : <P extends PropertyKey>(target: {}, property: P) => target is { [K in P]: unknown; }
4+
>target : {}
5+
>property : P
6+
7+
declare const arrayLikeOrIterable: ArrayLike<any> | Iterable<any>;
8+
>arrayLikeOrIterable : ArrayLike<any> | Iterable<any>
9+
10+
if (hasOwnProperty(arrayLikeOrIterable, 'length')) {
11+
>hasOwnProperty(arrayLikeOrIterable, 'length') : boolean
12+
>hasOwnProperty : <P extends PropertyKey>(target: {}, property: P) => target is { [K in P]: unknown; }
13+
>arrayLikeOrIterable : ArrayLike<any> | Iterable<any>
14+
>'length' : "length"
15+
16+
let x: number = arrayLikeOrIterable.length;
17+
>x : number
18+
>arrayLikeOrIterable.length : number
19+
>arrayLikeOrIterable : ArrayLike<any>
20+
>length : number
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//// [typeGuardNarrowByUntypedField.ts]
2+
declare function hasOwnProperty<P extends PropertyKey>(target: {}, property: P): target is { readonly [K in P]: unknown };
3+
declare const arrayLikeOrIterable: ArrayLike<any> | Iterable<any>;
4+
if (hasOwnProperty(arrayLikeOrIterable, 'length')) {
5+
let x: number = arrayLikeOrIterable.length;
6+
}
7+
8+
//// [typeGuardNarrowByUntypedField.js]
9+
if (hasOwnProperty(arrayLikeOrIterable, 'length')) {
10+
var x = arrayLikeOrIterable.length;
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
=== tests/cases/compiler/typeGuardNarrowByUntypedField.ts ===
2+
declare function hasOwnProperty<P extends PropertyKey>(target: {}, property: P): target is { readonly [K in P]: unknown };
3+
>hasOwnProperty : Symbol(hasOwnProperty, Decl(typeGuardNarrowByUntypedField.ts, 0, 0))
4+
>P : Symbol(P, Decl(typeGuardNarrowByUntypedField.ts, 0, 32))
5+
>PropertyKey : Symbol(PropertyKey, Decl(lib.es5.d.ts, --, --))
6+
>target : Symbol(target, Decl(typeGuardNarrowByUntypedField.ts, 0, 55))
7+
>property : Symbol(property, Decl(typeGuardNarrowByUntypedField.ts, 0, 66))
8+
>P : Symbol(P, Decl(typeGuardNarrowByUntypedField.ts, 0, 32))
9+
>target : Symbol(target, Decl(typeGuardNarrowByUntypedField.ts, 0, 55))
10+
>K : Symbol(K, Decl(typeGuardNarrowByUntypedField.ts, 0, 103))
11+
>P : Symbol(P, Decl(typeGuardNarrowByUntypedField.ts, 0, 32))
12+
13+
declare const arrayLikeOrIterable: ArrayLike<any> | Iterable<any>;
14+
>arrayLikeOrIterable : Symbol(arrayLikeOrIterable, Decl(typeGuardNarrowByUntypedField.ts, 1, 13))
15+
>ArrayLike : Symbol(ArrayLike, Decl(lib.es5.d.ts, --, --))
16+
>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --))
17+
18+
if (hasOwnProperty(arrayLikeOrIterable, 'length')) {
19+
>hasOwnProperty : Symbol(hasOwnProperty, Decl(typeGuardNarrowByUntypedField.ts, 0, 0))
20+
>arrayLikeOrIterable : Symbol(arrayLikeOrIterable, Decl(typeGuardNarrowByUntypedField.ts, 1, 13))
21+
22+
let x: number = arrayLikeOrIterable.length;
23+
>x : Symbol(x, Decl(typeGuardNarrowByUntypedField.ts, 3, 7))
24+
>arrayLikeOrIterable.length : Symbol(ArrayLike.length, Decl(lib.es5.d.ts, --, --))
25+
>arrayLikeOrIterable : Symbol(arrayLikeOrIterable, Decl(typeGuardNarrowByUntypedField.ts, 1, 13))
26+
>length : Symbol(ArrayLike.length, Decl(lib.es5.d.ts, --, --))
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
=== tests/cases/compiler/typeGuardNarrowByUntypedField.ts ===
2+
declare function hasOwnProperty<P extends PropertyKey>(target: {}, property: P): target is { readonly [K in P]: unknown };
3+
>hasOwnProperty : <P extends PropertyKey>(target: {}, property: P) => target is { readonly [K in P]: unknown; }
4+
>target : {}
5+
>property : P
6+
7+
declare const arrayLikeOrIterable: ArrayLike<any> | Iterable<any>;
8+
>arrayLikeOrIterable : ArrayLike<any> | Iterable<any>
9+
10+
if (hasOwnProperty(arrayLikeOrIterable, 'length')) {
11+
>hasOwnProperty(arrayLikeOrIterable, 'length') : boolean
12+
>hasOwnProperty : <P extends PropertyKey>(target: {}, property: P) => target is { readonly [K in P]: unknown; }
13+
>arrayLikeOrIterable : ArrayLike<any> | Iterable<any>
14+
>'length' : "length"
15+
16+
let x: number = arrayLikeOrIterable.length;
17+
>x : number
18+
>arrayLikeOrIterable.length : number
19+
>arrayLikeOrIterable : ArrayLike<any>
20+
>length : number
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// @lib: es6
2+
declare function hasOwnProperty<P extends PropertyKey>(target: {}, property: P): target is { [K in P]: unknown };
3+
declare const arrayLikeOrIterable: ArrayLike<any> | Iterable<any>;
4+
if (hasOwnProperty(arrayLikeOrIterable, 'length')) {
5+
let x: number = arrayLikeOrIterable.length;
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// @lib: es6
2+
declare function hasOwnProperty<P extends PropertyKey>(target: {}, property: P): target is { readonly [K in P]: unknown };
3+
declare const arrayLikeOrIterable: ArrayLike<any> | Iterable<any>;
4+
if (hasOwnProperty(arrayLikeOrIterable, 'length')) {
5+
let x: number = arrayLikeOrIterable.length;
6+
}

0 commit comments

Comments
 (0)