diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 7079ecf8a48f7..968fbbb969a88 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -19747,9 +19747,10 @@ namespace ts {
// This ensures the subtype relationship is ordered, and preventing declaration order
// from deciding which type "wins" in union subtype reduction.
// They're still assignable to one another, since `readonly` doesn't affect assignability.
+ // This is only applied during the strictSubtypeRelation -- currently used in subtype reduction
if (
- (relation === subtypeRelation || relation === strictSubtypeRelation) &&
- !!(sourcePropFlags & ModifierFlags.Readonly) && !(targetPropFlags & ModifierFlags.Readonly)
+ relation === strictSubtypeRelation &&
+ isReadonlySymbol(sourceProp) && !isReadonlySymbol(targetProp)
) {
return Ternary.False;
}
diff --git a/tests/baselines/reference/typeGuardNarrowByMutableUntypedField.js b/tests/baselines/reference/typeGuardNarrowByMutableUntypedField.js
new file mode 100644
index 0000000000000..58f403ff806c2
--- /dev/null
+++ b/tests/baselines/reference/typeGuardNarrowByMutableUntypedField.js
@@ -0,0 +1,11 @@
+//// [typeGuardNarrowByMutableUntypedField.ts]
+declare function hasOwnProperty
(target: {}, property: P): target is { [K in P]: unknown };
+declare const arrayLikeOrIterable: ArrayLike | Iterable;
+if (hasOwnProperty(arrayLikeOrIterable, 'length')) {
+ let x: number = arrayLikeOrIterable.length;
+}
+
+//// [typeGuardNarrowByMutableUntypedField.js]
+if (hasOwnProperty(arrayLikeOrIterable, 'length')) {
+ var x = arrayLikeOrIterable.length;
+}
diff --git a/tests/baselines/reference/typeGuardNarrowByMutableUntypedField.symbols b/tests/baselines/reference/typeGuardNarrowByMutableUntypedField.symbols
new file mode 100644
index 0000000000000..6c4720296ccd0
--- /dev/null
+++ b/tests/baselines/reference/typeGuardNarrowByMutableUntypedField.symbols
@@ -0,0 +1,27 @@
+=== tests/cases/compiler/typeGuardNarrowByMutableUntypedField.ts ===
+declare function hasOwnProperty(target: {}, property: P): target is { [K in P]: unknown };
+>hasOwnProperty : Symbol(hasOwnProperty, Decl(typeGuardNarrowByMutableUntypedField.ts, 0, 0))
+>P : Symbol(P, Decl(typeGuardNarrowByMutableUntypedField.ts, 0, 32))
+>PropertyKey : Symbol(PropertyKey, Decl(lib.es5.d.ts, --, --))
+>target : Symbol(target, Decl(typeGuardNarrowByMutableUntypedField.ts, 0, 55))
+>property : Symbol(property, Decl(typeGuardNarrowByMutableUntypedField.ts, 0, 66))
+>P : Symbol(P, Decl(typeGuardNarrowByMutableUntypedField.ts, 0, 32))
+>target : Symbol(target, Decl(typeGuardNarrowByMutableUntypedField.ts, 0, 55))
+>K : Symbol(K, Decl(typeGuardNarrowByMutableUntypedField.ts, 0, 94))
+>P : Symbol(P, Decl(typeGuardNarrowByMutableUntypedField.ts, 0, 32))
+
+declare const arrayLikeOrIterable: ArrayLike | Iterable;
+>arrayLikeOrIterable : Symbol(arrayLikeOrIterable, Decl(typeGuardNarrowByMutableUntypedField.ts, 1, 13))
+>ArrayLike : Symbol(ArrayLike, Decl(lib.es5.d.ts, --, --))
+>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --))
+
+if (hasOwnProperty(arrayLikeOrIterable, 'length')) {
+>hasOwnProperty : Symbol(hasOwnProperty, Decl(typeGuardNarrowByMutableUntypedField.ts, 0, 0))
+>arrayLikeOrIterable : Symbol(arrayLikeOrIterable, Decl(typeGuardNarrowByMutableUntypedField.ts, 1, 13))
+
+ let x: number = arrayLikeOrIterable.length;
+>x : Symbol(x, Decl(typeGuardNarrowByMutableUntypedField.ts, 3, 7))
+>arrayLikeOrIterable.length : Symbol(ArrayLike.length, Decl(lib.es5.d.ts, --, --))
+>arrayLikeOrIterable : Symbol(arrayLikeOrIterable, Decl(typeGuardNarrowByMutableUntypedField.ts, 1, 13))
+>length : Symbol(ArrayLike.length, Decl(lib.es5.d.ts, --, --))
+}
diff --git a/tests/baselines/reference/typeGuardNarrowByMutableUntypedField.types b/tests/baselines/reference/typeGuardNarrowByMutableUntypedField.types
new file mode 100644
index 0000000000000..46231c8ff6b44
--- /dev/null
+++ b/tests/baselines/reference/typeGuardNarrowByMutableUntypedField.types
@@ -0,0 +1,21 @@
+=== tests/cases/compiler/typeGuardNarrowByMutableUntypedField.ts ===
+declare function hasOwnProperty(target: {}, property: P): target is { [K in P]: unknown };
+>hasOwnProperty :
(target: {}, property: P) => target is { [K in P]: unknown; }
+>target : {}
+>property : P
+
+declare const arrayLikeOrIterable: ArrayLike | Iterable;
+>arrayLikeOrIterable : ArrayLike | Iterable
+
+if (hasOwnProperty(arrayLikeOrIterable, 'length')) {
+>hasOwnProperty(arrayLikeOrIterable, 'length') : boolean
+>hasOwnProperty : (target: {}, property: P) => target is { [K in P]: unknown; }
+>arrayLikeOrIterable : ArrayLike | Iterable
+>'length' : "length"
+
+ let x: number = arrayLikeOrIterable.length;
+>x : number
+>arrayLikeOrIterable.length : number
+>arrayLikeOrIterable : ArrayLike
+>length : number
+}
diff --git a/tests/baselines/reference/typeGuardNarrowByUntypedField.js b/tests/baselines/reference/typeGuardNarrowByUntypedField.js
new file mode 100644
index 0000000000000..8c2a90c334782
--- /dev/null
+++ b/tests/baselines/reference/typeGuardNarrowByUntypedField.js
@@ -0,0 +1,11 @@
+//// [typeGuardNarrowByUntypedField.ts]
+declare function hasOwnProperty(target: {}, property: P): target is { readonly [K in P]: unknown };
+declare const arrayLikeOrIterable: ArrayLike | Iterable;
+if (hasOwnProperty(arrayLikeOrIterable, 'length')) {
+ let x: number = arrayLikeOrIterable.length;
+}
+
+//// [typeGuardNarrowByUntypedField.js]
+if (hasOwnProperty(arrayLikeOrIterable, 'length')) {
+ var x = arrayLikeOrIterable.length;
+}
diff --git a/tests/baselines/reference/typeGuardNarrowByUntypedField.symbols b/tests/baselines/reference/typeGuardNarrowByUntypedField.symbols
new file mode 100644
index 0000000000000..0bf7a8b6b2546
--- /dev/null
+++ b/tests/baselines/reference/typeGuardNarrowByUntypedField.symbols
@@ -0,0 +1,27 @@
+=== tests/cases/compiler/typeGuardNarrowByUntypedField.ts ===
+declare function hasOwnProperty(target: {}, property: P): target is { readonly [K in P]: unknown };
+>hasOwnProperty : Symbol(hasOwnProperty, Decl(typeGuardNarrowByUntypedField.ts, 0, 0))
+>P : Symbol(P, Decl(typeGuardNarrowByUntypedField.ts, 0, 32))
+>PropertyKey : Symbol(PropertyKey, Decl(lib.es5.d.ts, --, --))
+>target : Symbol(target, Decl(typeGuardNarrowByUntypedField.ts, 0, 55))
+>property : Symbol(property, Decl(typeGuardNarrowByUntypedField.ts, 0, 66))
+>P : Symbol(P, Decl(typeGuardNarrowByUntypedField.ts, 0, 32))
+>target : Symbol(target, Decl(typeGuardNarrowByUntypedField.ts, 0, 55))
+>K : Symbol(K, Decl(typeGuardNarrowByUntypedField.ts, 0, 103))
+>P : Symbol(P, Decl(typeGuardNarrowByUntypedField.ts, 0, 32))
+
+declare const arrayLikeOrIterable: ArrayLike | Iterable;
+>arrayLikeOrIterable : Symbol(arrayLikeOrIterable, Decl(typeGuardNarrowByUntypedField.ts, 1, 13))
+>ArrayLike : Symbol(ArrayLike, Decl(lib.es5.d.ts, --, --))
+>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --))
+
+if (hasOwnProperty(arrayLikeOrIterable, 'length')) {
+>hasOwnProperty : Symbol(hasOwnProperty, Decl(typeGuardNarrowByUntypedField.ts, 0, 0))
+>arrayLikeOrIterable : Symbol(arrayLikeOrIterable, Decl(typeGuardNarrowByUntypedField.ts, 1, 13))
+
+ let x: number = arrayLikeOrIterable.length;
+>x : Symbol(x, Decl(typeGuardNarrowByUntypedField.ts, 3, 7))
+>arrayLikeOrIterable.length : Symbol(ArrayLike.length, Decl(lib.es5.d.ts, --, --))
+>arrayLikeOrIterable : Symbol(arrayLikeOrIterable, Decl(typeGuardNarrowByUntypedField.ts, 1, 13))
+>length : Symbol(ArrayLike.length, Decl(lib.es5.d.ts, --, --))
+}
diff --git a/tests/baselines/reference/typeGuardNarrowByUntypedField.types b/tests/baselines/reference/typeGuardNarrowByUntypedField.types
new file mode 100644
index 0000000000000..f44fea6b0f2d2
--- /dev/null
+++ b/tests/baselines/reference/typeGuardNarrowByUntypedField.types
@@ -0,0 +1,21 @@
+=== tests/cases/compiler/typeGuardNarrowByUntypedField.ts ===
+declare function hasOwnProperty(target: {}, property: P): target is { readonly [K in P]: unknown };
+>hasOwnProperty :
(target: {}, property: P) => target is { readonly [K in P]: unknown; }
+>target : {}
+>property : P
+
+declare const arrayLikeOrIterable: ArrayLike | Iterable;
+>arrayLikeOrIterable : ArrayLike | Iterable
+
+if (hasOwnProperty(arrayLikeOrIterable, 'length')) {
+>hasOwnProperty(arrayLikeOrIterable, 'length') : boolean
+>hasOwnProperty : (target: {}, property: P) => target is { readonly [K in P]: unknown; }
+>arrayLikeOrIterable : ArrayLike | Iterable
+>'length' : "length"
+
+ let x: number = arrayLikeOrIterable.length;
+>x : number
+>arrayLikeOrIterable.length : number
+>arrayLikeOrIterable : ArrayLike
+>length : number
+}
diff --git a/tests/cases/compiler/typeGuardNarrowByMutableUntypedField.ts b/tests/cases/compiler/typeGuardNarrowByMutableUntypedField.ts
new file mode 100644
index 0000000000000..1a585159d8a6d
--- /dev/null
+++ b/tests/cases/compiler/typeGuardNarrowByMutableUntypedField.ts
@@ -0,0 +1,6 @@
+// @lib: es6
+declare function hasOwnProperty(target: {}, property: P): target is { [K in P]: unknown };
+declare const arrayLikeOrIterable: ArrayLike | Iterable;
+if (hasOwnProperty(arrayLikeOrIterable, 'length')) {
+ let x: number = arrayLikeOrIterable.length;
+}
\ No newline at end of file
diff --git a/tests/cases/compiler/typeGuardNarrowByUntypedField.ts b/tests/cases/compiler/typeGuardNarrowByUntypedField.ts
new file mode 100644
index 0000000000000..2bde0c945ece1
--- /dev/null
+++ b/tests/cases/compiler/typeGuardNarrowByUntypedField.ts
@@ -0,0 +1,6 @@
+// @lib: es6
+declare function hasOwnProperty(target: {}, property: P): target is { readonly [K in P]: unknown };
+declare const arrayLikeOrIterable: ArrayLike | Iterable;
+if (hasOwnProperty(arrayLikeOrIterable, 'length')) {
+ let x: number = arrayLikeOrIterable.length;
+}
\ No newline at end of file