diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b1f73584c4901..00b70416af4e5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12567,7 +12567,7 @@ namespace ts { } else { // An empty object type is related to any mapped type that includes a '?' modifier. - if (isPartialMappedType(target) && isEmptyObjectType(source)) { + if (relation !== subtypeRelation && isPartialMappedType(target) && isEmptyObjectType(source)) { return Ternary.True; } if (isGenericMappedType(target)) { diff --git a/tests/baselines/reference/partialTypeNarrowedToByTypeGuard.js b/tests/baselines/reference/partialTypeNarrowedToByTypeGuard.js new file mode 100644 index 0000000000000..82696f59a9058 --- /dev/null +++ b/tests/baselines/reference/partialTypeNarrowedToByTypeGuard.js @@ -0,0 +1,42 @@ +//// [partialTypeNarrowedToByTypeGuard.ts] +type Obj = {} | undefined; + +type User = { + email: string; + name: string; +}; + +type PartialUser = Partial; + +// type PartialUser = { +// email?: string; +// name?: string; +// }; + +function isUser(obj: Obj): obj is PartialUser { + return true; +} + +function getUserName(obj: Obj) { + if (isUser(obj)) { + return obj.name; + } + + return ''; +} + +//// [partialTypeNarrowedToByTypeGuard.js] +"use strict"; +// type PartialUser = { +// email?: string; +// name?: string; +// }; +function isUser(obj) { + return true; +} +function getUserName(obj) { + if (isUser(obj)) { + return obj.name; + } + return ''; +} diff --git a/tests/baselines/reference/partialTypeNarrowedToByTypeGuard.symbols b/tests/baselines/reference/partialTypeNarrowedToByTypeGuard.symbols new file mode 100644 index 0000000000000..b810e1c4501c5 --- /dev/null +++ b/tests/baselines/reference/partialTypeNarrowedToByTypeGuard.symbols @@ -0,0 +1,52 @@ +=== tests/cases/compiler/partialTypeNarrowedToByTypeGuard.ts === +type Obj = {} | undefined; +>Obj : Symbol(Obj, Decl(partialTypeNarrowedToByTypeGuard.ts, 0, 0)) + +type User = { +>User : Symbol(User, Decl(partialTypeNarrowedToByTypeGuard.ts, 0, 26)) + + email: string; +>email : Symbol(email, Decl(partialTypeNarrowedToByTypeGuard.ts, 2, 13)) + + name: string; +>name : Symbol(name, Decl(partialTypeNarrowedToByTypeGuard.ts, 3, 18)) + +}; + +type PartialUser = Partial; +>PartialUser : Symbol(PartialUser, Decl(partialTypeNarrowedToByTypeGuard.ts, 5, 2)) +>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --)) +>User : Symbol(User, Decl(partialTypeNarrowedToByTypeGuard.ts, 0, 26)) + +// type PartialUser = { +// email?: string; +// name?: string; +// }; + +function isUser(obj: Obj): obj is PartialUser { +>isUser : Symbol(isUser, Decl(partialTypeNarrowedToByTypeGuard.ts, 7, 33)) +>obj : Symbol(obj, Decl(partialTypeNarrowedToByTypeGuard.ts, 14, 16)) +>Obj : Symbol(Obj, Decl(partialTypeNarrowedToByTypeGuard.ts, 0, 0)) +>obj : Symbol(obj, Decl(partialTypeNarrowedToByTypeGuard.ts, 14, 16)) +>PartialUser : Symbol(PartialUser, Decl(partialTypeNarrowedToByTypeGuard.ts, 5, 2)) + + return true; +} + +function getUserName(obj: Obj) { +>getUserName : Symbol(getUserName, Decl(partialTypeNarrowedToByTypeGuard.ts, 16, 1)) +>obj : Symbol(obj, Decl(partialTypeNarrowedToByTypeGuard.ts, 18, 21)) +>Obj : Symbol(Obj, Decl(partialTypeNarrowedToByTypeGuard.ts, 0, 0)) + + if (isUser(obj)) { +>isUser : Symbol(isUser, Decl(partialTypeNarrowedToByTypeGuard.ts, 7, 33)) +>obj : Symbol(obj, Decl(partialTypeNarrowedToByTypeGuard.ts, 18, 21)) + + return obj.name; +>obj.name : Symbol(name, Decl(partialTypeNarrowedToByTypeGuard.ts, 3, 18)) +>obj : Symbol(obj, Decl(partialTypeNarrowedToByTypeGuard.ts, 18, 21)) +>name : Symbol(name, Decl(partialTypeNarrowedToByTypeGuard.ts, 3, 18)) + } + + return ''; +} diff --git a/tests/baselines/reference/partialTypeNarrowedToByTypeGuard.types b/tests/baselines/reference/partialTypeNarrowedToByTypeGuard.types new file mode 100644 index 0000000000000..bbf8f96904b8a --- /dev/null +++ b/tests/baselines/reference/partialTypeNarrowedToByTypeGuard.types @@ -0,0 +1,49 @@ +=== tests/cases/compiler/partialTypeNarrowedToByTypeGuard.ts === +type Obj = {} | undefined; +>Obj : Obj + +type User = { +>User : User + + email: string; +>email : string + + name: string; +>name : string + +}; + +type PartialUser = Partial; +>PartialUser : Partial + +// type PartialUser = { +// email?: string; +// name?: string; +// }; + +function isUser(obj: Obj): obj is PartialUser { +>isUser : (obj: Obj) => obj is Partial +>obj : Obj + + return true; +>true : true +} + +function getUserName(obj: Obj) { +>getUserName : (obj: Obj) => string | undefined +>obj : Obj + + if (isUser(obj)) { +>isUser(obj) : boolean +>isUser : (obj: Obj) => obj is Partial +>obj : Obj + + return obj.name; +>obj.name : string | undefined +>obj : Partial +>name : string | undefined + } + + return ''; +>'' : "" +} diff --git a/tests/cases/compiler/partialTypeNarrowedToByTypeGuard.ts b/tests/cases/compiler/partialTypeNarrowedToByTypeGuard.ts new file mode 100644 index 0000000000000..9d43723bab9bd --- /dev/null +++ b/tests/cases/compiler/partialTypeNarrowedToByTypeGuard.ts @@ -0,0 +1,26 @@ +// @strict: true +type Obj = {} | undefined; + +type User = { + email: string; + name: string; +}; + +type PartialUser = Partial; + +// type PartialUser = { +// email?: string; +// name?: string; +// }; + +function isUser(obj: Obj): obj is PartialUser { + return true; +} + +function getUserName(obj: Obj) { + if (isUser(obj)) { + return obj.name; + } + + return ''; +} \ No newline at end of file