Skip to content
Sarj Code Standards

no-contradictory-type-guard

Primitive type guards must agree with the builtin predicate they return.

Why

A guard annotation does not validate its implementation. Returning an incompatible primitive predicate check makes callers trust the wrong primitive; TypeIs also incorrectly excludes rejected target values in the false branch.

Fix

Align the declared target and runtime test. For an intentional partial predicate, TypeGuard may narrow only the true branch; TypeIs must recognize every target value admitted by its input. Review callers before changing the narrowing contract.

Examples

Before — flagged An integer test does not prove a string
app/guards.py
from typing import TypeGuard
def is_text(value: object) -> TypeGuard[str]:
return isinstance(value, int)
After — preferred Recognize the primitive promised to callers
app/guards.py
from typing import TypeGuard
def is_text(value: object) -> TypeGuard[str]:
return isinstance(value, str)
Before — flagged A constant result does not prove a primitive type
app/guards.py
from typing import TypeGuard
def is_text(value: object) -> TypeGuard[str]:
return True
After — preferred TypeGuard can intentionally recognize no inputs
app/guards.py
from typing import TypeGuard
def is_text(value: object) -> TypeGuard[str]:
return False