• Sound mode S-07, pre-alpha
  • Design record 0007, Accepted

TSR0702

Type predicate '{0} is {1}' is not proved: when it returns false, '{0}' can still be '{1}'.

A type guard returns false for some values that are T, so callers would narrow them away wrongly. Make the false side exact or use is<T>().

Rule S-07: Type guards must be proved (level: sound). Reported by ts-r-check and ts-r-lsp in files that opt in to sound mode. See Sound mode.

What it means

Callers narrow a parameter to "not T" when a type predicate returns false. In a sound file, wherever the guard returns false, the parameter's flow type must fit that narrowed type. A guard like x === "a" for x is string returns false for other strings, which callers would then treat as numbers.

Example

Spec case from design record 0007 (checked by the record's case harness, not by this site's build)
// When this returns false, x can still be a string, but callers would narrow it to number.
function isString(x: string | number): x is string { // @expect TSR0702
  return x === "a";
}
function measure(v: string | number): number {
  return isString(v) ? v.length : v;
}
export const n: number = measure("b");

How to fix

  • Make the check match the predicate exactly: typeof x === "string" for x is string.
  • Or narrow the predicate to what the body checks (x is "a").

Sound mode is defined in design record 0007 (accepted 2026-10-15).