Skip to content

Commit addeff3

Browse files
authored
Make the relationship between partial mapped types and the empty object not apply for subtype relationship (#29384)
1 parent b6ae492 commit addeff3

File tree

5 files changed

+170
-1
lines changed

5 files changed

+170
-1
lines changed

src/compiler/checker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12677,7 +12677,7 @@ namespace ts {
1267712677
}
1267812678
else {
1267912679
// An empty object type is related to any mapped type that includes a '?' modifier.
12680-
if (isPartialMappedType(target) && isEmptyObjectType(source)) {
12680+
if (relation !== subtypeRelation && isPartialMappedType(target) && isEmptyObjectType(source)) {
1268112681
return Ternary.True;
1268212682
}
1268312683
if (isGenericMappedType(target)) {
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//// [partialTypeNarrowedToByTypeGuard.ts]
2+
type Obj = {} | undefined;
3+
4+
type User = {
5+
email: string;
6+
name: string;
7+
};
8+
9+
type PartialUser = Partial<User>;
10+
11+
// type PartialUser = {
12+
// email?: string;
13+
// name?: string;
14+
// };
15+
16+
function isUser(obj: Obj): obj is PartialUser {
17+
return true;
18+
}
19+
20+
function getUserName(obj: Obj) {
21+
if (isUser(obj)) {
22+
return obj.name;
23+
}
24+
25+
return '';
26+
}
27+
28+
//// [partialTypeNarrowedToByTypeGuard.js]
29+
"use strict";
30+
// type PartialUser = {
31+
// email?: string;
32+
// name?: string;
33+
// };
34+
function isUser(obj) {
35+
return true;
36+
}
37+
function getUserName(obj) {
38+
if (isUser(obj)) {
39+
return obj.name;
40+
}
41+
return '';
42+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
=== tests/cases/compiler/partialTypeNarrowedToByTypeGuard.ts ===
2+
type Obj = {} | undefined;
3+
>Obj : Symbol(Obj, Decl(partialTypeNarrowedToByTypeGuard.ts, 0, 0))
4+
5+
type User = {
6+
>User : Symbol(User, Decl(partialTypeNarrowedToByTypeGuard.ts, 0, 26))
7+
8+
email: string;
9+
>email : Symbol(email, Decl(partialTypeNarrowedToByTypeGuard.ts, 2, 13))
10+
11+
name: string;
12+
>name : Symbol(name, Decl(partialTypeNarrowedToByTypeGuard.ts, 3, 18))
13+
14+
};
15+
16+
type PartialUser = Partial<User>;
17+
>PartialUser : Symbol(PartialUser, Decl(partialTypeNarrowedToByTypeGuard.ts, 5, 2))
18+
>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --))
19+
>User : Symbol(User, Decl(partialTypeNarrowedToByTypeGuard.ts, 0, 26))
20+
21+
// type PartialUser = {
22+
// email?: string;
23+
// name?: string;
24+
// };
25+
26+
function isUser(obj: Obj): obj is PartialUser {
27+
>isUser : Symbol(isUser, Decl(partialTypeNarrowedToByTypeGuard.ts, 7, 33))
28+
>obj : Symbol(obj, Decl(partialTypeNarrowedToByTypeGuard.ts, 14, 16))
29+
>Obj : Symbol(Obj, Decl(partialTypeNarrowedToByTypeGuard.ts, 0, 0))
30+
>obj : Symbol(obj, Decl(partialTypeNarrowedToByTypeGuard.ts, 14, 16))
31+
>PartialUser : Symbol(PartialUser, Decl(partialTypeNarrowedToByTypeGuard.ts, 5, 2))
32+
33+
return true;
34+
}
35+
36+
function getUserName(obj: Obj) {
37+
>getUserName : Symbol(getUserName, Decl(partialTypeNarrowedToByTypeGuard.ts, 16, 1))
38+
>obj : Symbol(obj, Decl(partialTypeNarrowedToByTypeGuard.ts, 18, 21))
39+
>Obj : Symbol(Obj, Decl(partialTypeNarrowedToByTypeGuard.ts, 0, 0))
40+
41+
if (isUser(obj)) {
42+
>isUser : Symbol(isUser, Decl(partialTypeNarrowedToByTypeGuard.ts, 7, 33))
43+
>obj : Symbol(obj, Decl(partialTypeNarrowedToByTypeGuard.ts, 18, 21))
44+
45+
return obj.name;
46+
>obj.name : Symbol(name, Decl(partialTypeNarrowedToByTypeGuard.ts, 3, 18))
47+
>obj : Symbol(obj, Decl(partialTypeNarrowedToByTypeGuard.ts, 18, 21))
48+
>name : Symbol(name, Decl(partialTypeNarrowedToByTypeGuard.ts, 3, 18))
49+
}
50+
51+
return '';
52+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
=== tests/cases/compiler/partialTypeNarrowedToByTypeGuard.ts ===
2+
type Obj = {} | undefined;
3+
>Obj : Obj
4+
5+
type User = {
6+
>User : User
7+
8+
email: string;
9+
>email : string
10+
11+
name: string;
12+
>name : string
13+
14+
};
15+
16+
type PartialUser = Partial<User>;
17+
>PartialUser : Partial<User>
18+
19+
// type PartialUser = {
20+
// email?: string;
21+
// name?: string;
22+
// };
23+
24+
function isUser(obj: Obj): obj is PartialUser {
25+
>isUser : (obj: Obj) => obj is Partial<User>
26+
>obj : Obj
27+
28+
return true;
29+
>true : true
30+
}
31+
32+
function getUserName(obj: Obj) {
33+
>getUserName : (obj: Obj) => string | undefined
34+
>obj : Obj
35+
36+
if (isUser(obj)) {
37+
>isUser(obj) : boolean
38+
>isUser : (obj: Obj) => obj is Partial<User>
39+
>obj : Obj
40+
41+
return obj.name;
42+
>obj.name : string | undefined
43+
>obj : Partial<User>
44+
>name : string | undefined
45+
}
46+
47+
return '';
48+
>'' : ""
49+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// @strict: true
2+
type Obj = {} | undefined;
3+
4+
type User = {
5+
email: string;
6+
name: string;
7+
};
8+
9+
type PartialUser = Partial<User>;
10+
11+
// type PartialUser = {
12+
// email?: string;
13+
// name?: string;
14+
// };
15+
16+
function isUser(obj: Obj): obj is PartialUser {
17+
return true;
18+
}
19+
20+
function getUserName(obj: Obj) {
21+
if (isUser(obj)) {
22+
return obj.name;
23+
}
24+
25+
return '';
26+
}

0 commit comments

Comments
 (0)