Skip to content

No Chained Type Assertions

Error
small-rules/no-chained-type-assertions

Disallow chained TypeScript as and angle-bracket assertions, including parenthesized chains.

Rationale

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.

Diagnostic Messages

chained
This assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.

Configuration

This rule accepts one options object after the severity.

allowedTargetsOptional

Identifier names allowed as the final target of a single `as unknown/any/never as T` bridge, e.g. `vector` or `Vector3`.

{
"jsPlugins": [
"@pobammer-ts/small-rules"
],
"rules": {
"small-rules/no-chained-type-assertions": [
"error",
{
"allowedTargets": []
}
]
}
}

Examples

chained as assertions
const x = value as string as number;
satisfies instead of a second assertion
const x = value satisfies string;