diff --git a/package.json b/package.json index ad629ace064c5..cde432734bf12 100644 --- a/package.json +++ b/package.json @@ -114,5 +114,7 @@ "volta": { "node": "20.1.0", "npm": "8.19.4" + }, + "dependencies": { } } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 75be36474222f..eab2dbbdb0cf1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -25681,6 +25681,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getDefinitelyFalsyPartOfType(type: Type): Type { + if (type.flags & TypeFlags.TypeParameter) { + const constraint = getBaseConstraintOfType(type); + if (!constraint || constraint === type) { + return neverType; + } + return getDefinitelyFalsyPartOfType(constraint); + } + return type.flags & TypeFlags.String ? emptyStringType : type.flags & TypeFlags.Number ? zeroType : type.flags & TypeFlags.BigInt ? zeroBigIntType : diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 23f8d844c9856..a0f0930e44a2e 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -1003,8 +1003,8 @@ function callbackRefProject( cb: (refProj: ConfiguredProject) => T | undefined, refPath: P | undefined, ) { - const refProject = refPath && project.projectService.configuredProjects.get(refPath); - return refProject && cb(refProject); + const refProject = refPath ? project.projectService.configuredProjects.get(refPath) : undefined; + return refProject ? cb(refProject) : undefined; } function forEachReferencedProject( diff --git a/tests/baselines/reference/andAndGeneric.js b/tests/baselines/reference/andAndGeneric.js new file mode 100644 index 0000000000000..574d40dd67012 --- /dev/null +++ b/tests/baselines/reference/andAndGeneric.js @@ -0,0 +1,28 @@ +//// [tests/cases/compiler/andAndGeneric.ts] //// + +//// [andAndGeneric.ts] +declare function id(x: T): T; + +function f(x: T) { + return id(x && x); // should NOT be narrowed to NonNullable +} + +// ---- expected types ---- +const t1 = f(null); // null (currently incorrectly NonNullable -> never) +const t2 = f(0); // 0 +const t3 = f(1); // 1 +const t4 = f<"a" | null>("a"); // "a" +const t5 = f<"a" | null>(null); // null + + +//// [andAndGeneric.js] +"use strict"; +function f(x) { + return id(x && x); // should NOT be narrowed to NonNullable +} +// ---- expected types ---- +var t1 = f(null); // null (currently incorrectly NonNullable -> never) +var t2 = f(0); // 0 +var t3 = f(1); // 1 +var t4 = f("a"); // "a" +var t5 = f(null); // null diff --git a/tests/baselines/reference/andAndGeneric.symbols b/tests/baselines/reference/andAndGeneric.symbols new file mode 100644 index 0000000000000..70afde5e2c2e6 --- /dev/null +++ b/tests/baselines/reference/andAndGeneric.symbols @@ -0,0 +1,43 @@ +//// [tests/cases/compiler/andAndGeneric.ts] //// + +=== andAndGeneric.ts === +declare function id(x: T): T; +>id : Symbol(id, Decl(andAndGeneric.ts, 0, 0)) +>T : Symbol(T, Decl(andAndGeneric.ts, 0, 20)) +>x : Symbol(x, Decl(andAndGeneric.ts, 0, 23)) +>T : Symbol(T, Decl(andAndGeneric.ts, 0, 20)) +>T : Symbol(T, Decl(andAndGeneric.ts, 0, 20)) + +function f(x: T) { +>f : Symbol(f, Decl(andAndGeneric.ts, 0, 32)) +>T : Symbol(T, Decl(andAndGeneric.ts, 2, 11)) +>x : Symbol(x, Decl(andAndGeneric.ts, 2, 14)) +>T : Symbol(T, Decl(andAndGeneric.ts, 2, 11)) + + return id(x && x); // should NOT be narrowed to NonNullable +>id : Symbol(id, Decl(andAndGeneric.ts, 0, 0)) +>x : Symbol(x, Decl(andAndGeneric.ts, 2, 14)) +>x : Symbol(x, Decl(andAndGeneric.ts, 2, 14)) +} + +// ---- expected types ---- +const t1 = f(null); // null (currently incorrectly NonNullable -> never) +>t1 : Symbol(t1, Decl(andAndGeneric.ts, 7, 5)) +>f : Symbol(f, Decl(andAndGeneric.ts, 0, 32)) + +const t2 = f(0); // 0 +>t2 : Symbol(t2, Decl(andAndGeneric.ts, 8, 5)) +>f : Symbol(f, Decl(andAndGeneric.ts, 0, 32)) + +const t3 = f(1); // 1 +>t3 : Symbol(t3, Decl(andAndGeneric.ts, 9, 5)) +>f : Symbol(f, Decl(andAndGeneric.ts, 0, 32)) + +const t4 = f<"a" | null>("a"); // "a" +>t4 : Symbol(t4, Decl(andAndGeneric.ts, 10, 5)) +>f : Symbol(f, Decl(andAndGeneric.ts, 0, 32)) + +const t5 = f<"a" | null>(null); // null +>t5 : Symbol(t5, Decl(andAndGeneric.ts, 11, 5)) +>f : Symbol(f, Decl(andAndGeneric.ts, 0, 32)) + diff --git a/tests/baselines/reference/andAndGeneric.types b/tests/baselines/reference/andAndGeneric.types new file mode 100644 index 0000000000000..f4560a176b07f --- /dev/null +++ b/tests/baselines/reference/andAndGeneric.types @@ -0,0 +1,75 @@ +//// [tests/cases/compiler/andAndGeneric.ts] //// + +=== andAndGeneric.ts === +declare function id(x: T): T; +>id : (x: T) => T +> : ^ ^^ ^^ ^^^^^ +>x : T +> : ^ + +function f(x: T) { +>f : (x: T) => NonNullable +> : ^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^ +>x : T +> : ^ + + return id(x && x); // should NOT be narrowed to NonNullable +>id(x && x) : NonNullable +> : ^^^^^^^^^^^^^^ +>id : (x: T_1) => T_1 +> : ^^^^^^ ^^ ^^^^^ +>x && x : NonNullable +> : ^^^^^^^^^^^^^^ +>x : T +> : ^ +>x : NonNullable +> : ^^^^^^^^^^^^^^ +} + +// ---- expected types ---- +const t1 = f(null); // null (currently incorrectly NonNullable -> never) +>t1 : never +> : ^^^^^ +>f(null) : never +> : ^^^^^ +>f : (x: T) => NonNullable +> : ^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^ + +const t2 = f(0); // 0 +>t2 : 0 +> : ^ +>f(0) : 0 +> : ^ +>f : (x: T) => NonNullable +> : ^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^ +>0 : 0 +> : ^ + +const t3 = f(1); // 1 +>t3 : 1 +> : ^ +>f(1) : 1 +> : ^ +>f : (x: T) => NonNullable +> : ^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^ +>1 : 1 +> : ^ + +const t4 = f<"a" | null>("a"); // "a" +>t4 : "a" +> : ^^^ +>f<"a" | null>("a") : "a" +> : ^^^ +>f : (x: T) => NonNullable +> : ^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^ +>"a" : "a" +> : ^^^ + +const t5 = f<"a" | null>(null); // null +>t5 : "a" +> : ^^^ +>f<"a" | null>(null) : "a" +> : ^^^ +>f : (x: T) => NonNullable +> : ^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/cases/compiler/andAndGeneric.ts b/tests/cases/compiler/andAndGeneric.ts new file mode 100644 index 0000000000000..e5fffe4dc6fc8 --- /dev/null +++ b/tests/cases/compiler/andAndGeneric.ts @@ -0,0 +1,14 @@ +// @strict: true + +declare function id(x: T): T; + +function f(x: T) { + return id(x && x); // should NOT be narrowed to NonNullable +} + +// ---- expected types ---- +const t1 = f(null); // null (currently incorrectly NonNullable -> never) +const t2 = f(0); // 0 +const t3 = f(1); // 1 +const t4 = f<"a" | null>("a"); // "a" +const t5 = f<"a" | null>(null); // null