Skip to content

Commit c647b9b

Browse files
committed
feat: enhance type checking by excluding nullish types in assignability checks
1 parent 2e3f1c0 commit c647b9b

2 files changed

Lines changed: 21 additions & 4 deletions

File tree

src/util/nodes.util.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,16 @@ const createNodeFunctionIfCompatible = (
7979
// Simplify the return type by resolving type parameters
8080
const simplifiedReturnType = resolveReturnType(checker, returnType);
8181

82-
// Only proceed if the return type is assignable to the target parameter type
83-
if (!checker.isTypeAssignableTo(simplifiedReturnType, paramType)) {
82+
// Only proceed if the return type is assignable to the target parameter type.
83+
// The nullish part of the return type is ignored: a function returning
84+
// `string | null` is still a valid suggestion for a plain `string` parameter.
85+
// A purely nullish return type strips down to `never` (assignable to anything),
86+
// so it must be excluded explicitly.
87+
const nonNullableReturnType = checker.getNonNullableType(simplifiedReturnType);
88+
if (
89+
(nonNullableReturnType.flags & ts.TypeFlags.Never) !== 0 ||
90+
!checker.isTypeAssignableTo(nonNullableReturnType, paramType)
91+
) {
8492
return null;
8593
}
8694

src/util/references.util.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,8 +257,17 @@ const extractObjectProperties = (
257257
): Array<{ path: ReferencePath[]; type: ts.Type }> => {
258258
const results: Array<{ path: ReferencePath[]; type: ts.Type }> = [];
259259

260-
// Check if the current type matches the expected type
261-
if (checker.isTypeAssignableTo(type, expectedType)) {
260+
// Check if the current type matches the expected type. The nullish part of a
261+
// candidate is ignored: a reference typed `string | null` (or an optional
262+
// property `text?: string | null`) is still a valid suggestion for a plain
263+
// `string` parameter — strict assignability would reject it under strictNullChecks.
264+
// A purely nullish candidate strips down to `never` (assignable to anything),
265+
// so it must be excluded explicitly.
266+
const nonNullableType = checker.getNonNullableType(type);
267+
if (
268+
(nonNullableType.flags & ts.TypeFlags.Never) === 0 &&
269+
checker.isTypeAssignableTo(nonNullableType, expectedType)
270+
) {
262271
results.push({ path: currentPath, type });
263272
}
264273

0 commit comments

Comments
 (0)