From 4514067e6e7b959c479692aa97b24692bd313a24 Mon Sep 17 00:00:00 2001 From: Jack Robards Date: Mon, 20 Jan 2025 02:57:50 -0600 Subject: [PATCH] fix: Exclude null from the return type of ifDefined directive for newer versions of lit --- .changeset/lemon-fans-scream.md | 5 +++++ .../src/lib/rules/util/directive/get-directive.ts | 12 +++++++++--- .../src/test/rules/no-nullable-attribute-binding.ts | 8 ++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 .changeset/lemon-fans-scream.md diff --git a/.changeset/lemon-fans-scream.md b/.changeset/lemon-fans-scream.md new file mode 100644 index 00000000..1ce8b053 --- /dev/null +++ b/.changeset/lemon-fans-scream.md @@ -0,0 +1,5 @@ +--- +"lit-analyzer-fork": patch +--- + +Fix ifDefined logic to exclude null from the return type, instead of just undefined diff --git a/packages/lit-analyzer/src/lib/rules/util/directive/get-directive.ts b/packages/lit-analyzer/src/lib/rules/util/directive/get-directive.ts index 0d56693d..a39e1647 100644 --- a/packages/lit-analyzer/src/lib/rules/util/directive/get-directive.ts +++ b/packages/lit-analyzer/src/lib/rules/util/directive/get-directive.ts @@ -6,7 +6,7 @@ import { HtmlNodeAttrAssignmentKind } from "../../../analyze/types/html-node/htm import type { RuleModuleContext } from "../../../analyze/types/rule/rule-module-context.js"; import { lazy } from "../../../analyze/util/general-util.js"; import { removeUndefinedFromType } from "../type/remove-undefined-from-type.js"; -import { isLitDirective } from "./is-lit-directive.js"; +import { isLit1Directive, isLitDirective } from "./is-lit-directive.js"; export type BuiltInDirectiveKind = | "ifDefined" @@ -50,8 +50,14 @@ export function getDirective(assignment: HtmlNodeAttrAssignment, context: RuleMo // This new type becomes the actual type of the expression const actualType = lazy(() => { if (args.length >= 1) { - const returnType = toSimpleType(checker.getTypeAtLocation(args[0]), checker); - return removeUndefinedFromType(returnType); + const exprType = toSimpleType(checker.getTypeAtLocation(assignment.expression), checker); + + if (isLit1Directive(exprType)) { + const returnType = toSimpleType(checker.getTypeAtLocation(args[0]), checker); + return removeUndefinedFromType(returnType); + } + + return toSimpleType(checker.getNonNullableType(checker.getTypeAtLocation(args[0])), checker); } return undefined; diff --git a/packages/lit-analyzer/src/test/rules/no-nullable-attribute-binding.ts b/packages/lit-analyzer/src/test/rules/no-nullable-attribute-binding.ts index 3abe6c88..617ae0f3 100644 --- a/packages/lit-analyzer/src/test/rules/no-nullable-attribute-binding.ts +++ b/packages/lit-analyzer/src/test/rules/no-nullable-attribute-binding.ts @@ -26,6 +26,14 @@ tsTest("Can assign 'null' in property binding", t => { hasNoDiagnostics(t, diagnostics); }); +tsTest("Return type of `ifDefined` is not `null`", t => { + const { diagnostics } = getDiagnostics(` + const ifDefined = (x: T) => x ?? "non-null"; + html\`\`; + `); + hasNoDiagnostics(t, diagnostics); +}); + tsTest("Message for 'null' in attribute detects null type correctly", t => { const { diagnostics } = getDiagnostics('html``'); hasDiagnostic(t, diagnostics, "no-nullable-attribute-binding");