chainedThis assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.small-rules/no-chained-type-assertionsDisallow chained TypeScript as and angle-bracket assertions, including parenthesized chains.
Ported from dmmulroy/anti-slop’s
no-chained-type-assertions rule. It guards against the same casts that fabricate evidence. Credit for the
rule idea goes to its original author. This port matches the local checker and adds three cases.
Fabricated evidence: the second as, written as a keyword or as an angle-bracket assertion,
narrows nothing. It only discards whatever the first one claimed. value as string as number
proves neither type.
Boundary parsing over brute-forcing: when you see as unknown as T or as any as T the input is
probably untrusted. I’d rather you check it at the boundary with a guard or schema, then keep the precise
type from there. The cast hides a wrong assumption about the input instead of correcting it, so it’s
seldom the right fix.
Parenthesized chains count: wrapping the first assertion in parens doesn’t change anything:
(value as string) as number;The rule unwraps them, so you can’t hide it.
The as const allowance is the local difference. The rule allows as const as const, because const is idempotent
and there’s nothing for the second assertion to discard. You can also name specific identifier targets for one
as unknown as T bridge via allowedTargets. That’s for nominal twins like Roblox vector / Vector3, not
a free pass: as unknown as string still flags. Everything else with two non-const assertions is a problem.
chainedThis assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.This rule accepts one options object after the severity.
const x = value as string as number;const x = value satisfies string;