TypeScript Debugging

Preventing Unsafe TypeScript Assertions with ESLint

We recently pushed a hotfix after a runtime error slipped past our build pipeline. The culprit was a developer using an 'as' assertion to silence a compiler error, which effectively masked a data structure mismatch. I spent the afternoon exploring how to enforce stricter type safety using our existing linting infrastructure.

Need the supporting files, visual references, or downloadable resources that normally sit behind this kind of workflow?

Open on 3DCGHub

1. Identifying the Root Cause

The issue appeared when a service started returning null instead of an object, causing our frontend to crash while accessing properties. The code relied on an 'as' assertion to assume a specific shape, which bypassed the TypeScript compiler's attempt to warn us that the data could be empty.

I initially suspected a faulty API contract update, but the logs revealed that the TypeScript 'as' syntax had effectively silenced the type checker during development. By forcing a cast, the developer had essentially turned off the safety net that usually guards our UI components.

  • Analyzed the stack trace pointing to a property access on undefined
  • Traced the origin to a manual type cast in the data fetcher
  • Identified the lack of runtime validation as a secondary failure point

2. Investigating Existing Rules

My first thought was to hunt for a built-in rule in the standard ESLint set that forbids type assertions entirely. I checked the documentation, but quickly realized that TypeScript does not provide an 'on-by-default' rule to disable 'as' usage, as casting is occasionally necessary for complex intersections.

I looked into common plugins to see how other teams handle this. I wanted something that would allow specific, intentional assertions—like const assertions or casting to unknown—while blocking the sloppy 'as any' pattern that leads to production bugs.

  • Tested the standard rule sets for built-in restriction options
  • Consulted plugin repositories for type-assertion control
  • Considered the trade-off between strictness and developer velocity

3. Enforcing Consistency via typescript-eslint

I chose to implement 'consistent-type-assertions' within our 'typescript-eslint' configuration. This allowed me to define a 'never' policy, which triggers a warning whenever an 'as' keyword is detected. This forces developers to consider why they are overriding the compiler instead of fixing the underlying type definition.

Configuring this required updating our '.eslintrc.json' file. I set the rule to 'error' severity to ensure that nobody could accidentally bypass it without deliberate action in the configuration file itself.

  • Added consistent-type-assertions to the rules object
  • Configured the assertionStyle to 'never' for strict enforcement
  • Verified that existing code patterns triggered lint warnings immediately

4. Testing and Verification

Once the rule was live, I ran the linter across our entire repository. It surfaced several instances where type casting was used as a shortcut. I spent the next hour refactoring these modules to use proper type guards and explicit interfaces instead of assertions.

The improvement in code clarity was significant. By removing the 'as' overrides, the compiler correctly identified three other edge cases where our data shape was inconsistent. We no longer rely on 'trust me' casts in our data-fetching layer.

  • Executed a full repository lint check
  • Refactored identified problematic casts to use type guards
  • Verified that the build pipeline now fails on dangerous assertions

FAQ

Is it ever okay to use 'as'?

Yes, but only in specific scenarios like refining an 'unknown' type or performing a 'const' assertion. The goal is not to eliminate casting, but to eliminate lazy casting used to mask type errors.

Does this rule work with older TSLint configurations?

No, TSLint is deprecated. You should migrate to the 'typescript-eslint' plugin suite to use the modern 'consistent-type-assertions' rule.