Skip to content
Sarj Code Standards

no-partial-type-predicate

Do not give a partial primitive filter an explicit type predicate that excludes valid values in the false branch.

Why

Type predicates narrow both branches, and TypeScript trusts their implementation. A positive-number or non-empty-string predicate can return false for a value belonging to its promised type, causing callers to treat that value as a different type.

Fix

Use a boolean return for an intentional value filter, or recognize every member of the promised type. Preserve required callback and public contracts; a refined domain may need a distinct validated type. Recheck false-branch callers when changing a predicate.

Examples

Before — flagged A rejected UUID candidate can still be a string
src/guard.ts
import { z } from "zod";
export const UuidSchema: z.ZodUUID = z.uuid();
export function isUuid(value: unknown): value is string {
return UuidSchema.safeParse(value).success;
}
After — preferred Keep a UUID value filter boolean
src/filter.ts
import { z } from "zod";
export const UuidSchema: z.ZodUUID = z.uuid();
export function isUuid(value: unknown): boolean {
return UuidSchema.safeParse(value).success;
}
Before — flagged Zero remains a number when the predicate returns false
src/guard.ts
function isPositive(value: unknown): value is number {
return typeof value === "number" && value > 0;
}
After — preferred Keep an intentional value filter boolean
src/filter.ts
function isPositive(value: number): boolean {
return value > 0;
}

References