diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 04facba3196e7..34fd98bcbfe11 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -29404,8 +29404,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (checkDerived) { return filterType(type, t => !isTypeDerivedFrom(t, candidate)); } + type = type.flags & TypeFlags.Unknown ? unknownUnionType : type; const trueType = getNarrowedType(type, candidate, /*assumeTrue*/ true, /*checkDerived*/ false); - return filterType(type, t => !isTypeSubsetOf(t, trueType)); + return recombineUnknownType(filterType(type, t => !isTypeSubsetOf(t, trueType))); } if (type.flags & TypeFlags.AnyOrUnknown) { return candidate; diff --git a/tests/baselines/reference/narrowUnknownByTypePredicate.symbols b/tests/baselines/reference/narrowUnknownByTypePredicate.symbols new file mode 100644 index 0000000000000..9f0388f934c86 --- /dev/null +++ b/tests/baselines/reference/narrowUnknownByTypePredicate.symbols @@ -0,0 +1,89 @@ +//// [tests/cases/compiler/narrowUnknownByTypePredicate.ts] //// + +=== narrowUnknownByTypePredicate.ts === +declare function isNotNullish(value: unknown): value is {}; +>isNotNullish : Symbol(isNotNullish, Decl(narrowUnknownByTypePredicate.ts, 0, 0)) +>value : Symbol(value, Decl(narrowUnknownByTypePredicate.ts, 0, 30)) +>value : Symbol(value, Decl(narrowUnknownByTypePredicate.ts, 0, 30)) + +declare function isNullish(value: unknown): value is null | undefined; +>isNullish : Symbol(isNullish, Decl(narrowUnknownByTypePredicate.ts, 0, 59)) +>value : Symbol(value, Decl(narrowUnknownByTypePredicate.ts, 1, 27)) +>value : Symbol(value, Decl(narrowUnknownByTypePredicate.ts, 1, 27)) + +declare const value1: unknown; +>value1 : Symbol(value1, Decl(narrowUnknownByTypePredicate.ts, 3, 13)) + +if (isNotNullish(value1)) { +>isNotNullish : Symbol(isNotNullish, Decl(narrowUnknownByTypePredicate.ts, 0, 0)) +>value1 : Symbol(value1, Decl(narrowUnknownByTypePredicate.ts, 3, 13)) + + value1; +>value1 : Symbol(value1, Decl(narrowUnknownByTypePredicate.ts, 3, 13)) +} + +declare const value2: unknown; +>value2 : Symbol(value2, Decl(narrowUnknownByTypePredicate.ts, 8, 13)) + +if (!isNotNullish(value2)) { +>isNotNullish : Symbol(isNotNullish, Decl(narrowUnknownByTypePredicate.ts, 0, 0)) +>value2 : Symbol(value2, Decl(narrowUnknownByTypePredicate.ts, 8, 13)) + + value2; +>value2 : Symbol(value2, Decl(narrowUnknownByTypePredicate.ts, 8, 13)) +} + +declare const value3: unknown; +>value3 : Symbol(value3, Decl(narrowUnknownByTypePredicate.ts, 13, 13)) + +if (isNullish(value3)) { +>isNullish : Symbol(isNullish, Decl(narrowUnknownByTypePredicate.ts, 0, 59)) +>value3 : Symbol(value3, Decl(narrowUnknownByTypePredicate.ts, 13, 13)) + + value3; +>value3 : Symbol(value3, Decl(narrowUnknownByTypePredicate.ts, 13, 13)) +} + +declare const value4: unknown; +>value4 : Symbol(value4, Decl(narrowUnknownByTypePredicate.ts, 18, 13)) + +if (!isNullish(value4)) { +>isNullish : Symbol(isNullish, Decl(narrowUnknownByTypePredicate.ts, 0, 59)) +>value4 : Symbol(value4, Decl(narrowUnknownByTypePredicate.ts, 18, 13)) + + value4; +>value4 : Symbol(value4, Decl(narrowUnknownByTypePredicate.ts, 18, 13)) +} + +declare class A { foo: string; } +>A : Symbol(A, Decl(narrowUnknownByTypePredicate.ts, 21, 1)) +>foo : Symbol(A.foo, Decl(narrowUnknownByTypePredicate.ts, 23, 17)) + +declare function isA(value: unknown): value is A; +>isA : Symbol(isA, Decl(narrowUnknownByTypePredicate.ts, 23, 32)) +>value : Symbol(value, Decl(narrowUnknownByTypePredicate.ts, 24, 21)) +>value : Symbol(value, Decl(narrowUnknownByTypePredicate.ts, 24, 21)) +>A : Symbol(A, Decl(narrowUnknownByTypePredicate.ts, 21, 1)) + +declare const value5: unknown; +>value5 : Symbol(value5, Decl(narrowUnknownByTypePredicate.ts, 26, 13)) + +if (isA(value5)) { +>isA : Symbol(isA, Decl(narrowUnknownByTypePredicate.ts, 23, 32)) +>value5 : Symbol(value5, Decl(narrowUnknownByTypePredicate.ts, 26, 13)) + + value5; +>value5 : Symbol(value5, Decl(narrowUnknownByTypePredicate.ts, 26, 13)) +} + +declare const value6: unknown; +>value6 : Symbol(value6, Decl(narrowUnknownByTypePredicate.ts, 31, 13)) + +if (!isA(value6)) { +>isA : Symbol(isA, Decl(narrowUnknownByTypePredicate.ts, 23, 32)) +>value6 : Symbol(value6, Decl(narrowUnknownByTypePredicate.ts, 31, 13)) + + value6; +>value6 : Symbol(value6, Decl(narrowUnknownByTypePredicate.ts, 31, 13)) +} + diff --git a/tests/baselines/reference/narrowUnknownByTypePredicate.types b/tests/baselines/reference/narrowUnknownByTypePredicate.types new file mode 100644 index 0000000000000..43d8e0b936e4b --- /dev/null +++ b/tests/baselines/reference/narrowUnknownByTypePredicate.types @@ -0,0 +1,135 @@ +//// [tests/cases/compiler/narrowUnknownByTypePredicate.ts] //// + +=== narrowUnknownByTypePredicate.ts === +declare function isNotNullish(value: unknown): value is {}; +>isNotNullish : (value: unknown) => value is {} +> : ^ ^^ ^^^^^ +>value : unknown +> : ^^^^^^^ + +declare function isNullish(value: unknown): value is null | undefined; +>isNullish : (value: unknown) => value is null | undefined +> : ^ ^^ ^^^^^ +>value : unknown +> : ^^^^^^^ + +declare const value1: unknown; +>value1 : unknown +> : ^^^^^^^ + +if (isNotNullish(value1)) { +>isNotNullish(value1) : boolean +> : ^^^^^^^ +>isNotNullish : (value: unknown) => value is {} +> : ^ ^^ ^^^^^ +>value1 : unknown +> : ^^^^^^^ + + value1; +>value1 : {} +> : ^^ +} + +declare const value2: unknown; +>value2 : unknown +> : ^^^^^^^ + +if (!isNotNullish(value2)) { +>!isNotNullish(value2) : boolean +> : ^^^^^^^ +>isNotNullish(value2) : boolean +> : ^^^^^^^ +>isNotNullish : (value: unknown) => value is {} +> : ^ ^^ ^^^^^ +>value2 : unknown +> : ^^^^^^^ + + value2; +>value2 : null | undefined +> : ^^^^^^^^^^^^^^^^ +} + +declare const value3: unknown; +>value3 : unknown +> : ^^^^^^^ + +if (isNullish(value3)) { +>isNullish(value3) : boolean +> : ^^^^^^^ +>isNullish : (value: unknown) => value is null | undefined +> : ^ ^^ ^^^^^ +>value3 : unknown +> : ^^^^^^^ + + value3; +>value3 : null | undefined +> : ^^^^^^^^^^^^^^^^ +} + +declare const value4: unknown; +>value4 : unknown +> : ^^^^^^^ + +if (!isNullish(value4)) { +>!isNullish(value4) : boolean +> : ^^^^^^^ +>isNullish(value4) : boolean +> : ^^^^^^^ +>isNullish : (value: unknown) => value is null | undefined +> : ^ ^^ ^^^^^ +>value4 : unknown +> : ^^^^^^^ + + value4; +>value4 : {} +> : ^^ +} + +declare class A { foo: string; } +>A : A +> : ^ +>foo : string +> : ^^^^^^ + +declare function isA(value: unknown): value is A; +>isA : (value: unknown) => value is A +> : ^ ^^ ^^^^^ +>value : unknown +> : ^^^^^^^ + +declare const value5: unknown; +>value5 : unknown +> : ^^^^^^^ + +if (isA(value5)) { +>isA(value5) : boolean +> : ^^^^^^^ +>isA : (value: unknown) => value is A +> : ^ ^^ ^^^^^ +>value5 : unknown +> : ^^^^^^^ + + value5; +>value5 : A +> : ^ +} + +declare const value6: unknown; +>value6 : unknown +> : ^^^^^^^ + +if (!isA(value6)) { +>!isA(value6) : boolean +> : ^^^^^^^ +>isA(value6) : boolean +> : ^^^^^^^ +>isA : (value: unknown) => value is A +> : ^ ^^ ^^^^^ +>value6 : unknown +> : ^^^^^^^ + + value6; +>value6 : unknown +> : ^^^^^^^ +} + diff --git a/tests/cases/compiler/narrowUnknownByTypePredicate.ts b/tests/cases/compiler/narrowUnknownByTypePredicate.ts new file mode 100644 index 0000000000000..e952788b6a91a --- /dev/null +++ b/tests/cases/compiler/narrowUnknownByTypePredicate.ts @@ -0,0 +1,38 @@ +// @strict: true +// @noEmit: true + +declare function isNotNullish(value: unknown): value is {}; +declare function isNullish(value: unknown): value is null | undefined; + +declare const value1: unknown; +if (isNotNullish(value1)) { + value1; +} + +declare const value2: unknown; +if (!isNotNullish(value2)) { + value2; +} + +declare const value3: unknown; +if (isNullish(value3)) { + value3; +} + +declare const value4: unknown; +if (!isNullish(value4)) { + value4; +} + +declare class A { foo: string; } +declare function isA(value: unknown): value is A; + +declare const value5: unknown; +if (isA(value5)) { + value5; +} + +declare const value6: unknown; +if (!isA(value6)) { + value6; +}