Skip to content

TypeScript

TypeScript's power lies in its type system — but that power is easily undermined by any casts, missing return types, and non-null assertions. MCP Zen of Languages encodes 10 type-safety principles that catch the patterns where TypeScript's guarantees quietly erode.

Optional External Tool Augmentation

Consent-first external tooling

External tool execution is optional and disabled by default. Use --enable-external-tools (CLI) or enable_external_tools=true (MCP) to opt in. Missing tools should return recommendations; no automatic installs occur during analysis.

Tool Default invocation Output
biome biome lint --stdin-file-path stdin.ts --reporter json JSON
eslint eslint --stdin --format json JSON
prettier prettier --check --stdin-filepath stdin.ts Text / structured stderr

Temporary runner fallback

For temporary execution via package runners, use --allow-temporary-runners (CLI) or allow_temporary_runners=true (MCP).

Zen Principles

18 principles across 8 categories, drawn from Google TypeScript Style Guide.

Async · 1 principle Clarity · 1 principle Configuration · 1 principle Idioms · 6 principles Immutability · 1 principle Organization · 1 principle Readability · 1 principle Type Safety · 6 principles

Rule ID Principle Category Severity Dogma
ts-001 Avoid 'any' type Type Safety 9 ZEN-EXPLICIT-INTENT
ts-002 Use strict mode Configuration 9 ZEN-EXPLICIT-INTENT
ts-003 Prefer interfaces over type aliases for objects Idioms 5 ZEN-RIGHT-ABSTRACTION, ZEN-UNAMBIGUOUS-NAME, ZEN-PROPORTIONATE-COMPLEXITY
ts-004 Always specify return types Type Safety 7 ZEN-EXPLICIT-INTENT, ZEN-FAIL-FAST
ts-005 Use readonly when appropriate Immutability 6 ZEN-VISIBLE-STATE
ts-006 Leverage type guards Type Safety 7 ZEN-EXPLICIT-INTENT
ts-007 Use utility types Idioms 6 ZEN-RIGHT-ABSTRACTION
ts-008 Avoid non-null assertions Type Safety 8 ZEN-EXPLICIT-INTENT
ts-009 Use enums or const assertions appropriately Idioms 6 ZEN-RIGHT-ABSTRACTION
ts-010 Prefer unknown over any for uncertain types Type Safety 7 ZEN-EXPLICIT-INTENT, ZEN-FAIL-FAST
ts-011 Use optional chaining instead of manual null checks Idioms 5 ZEN-RIGHT-ABSTRACTION, ZEN-RETURN-EARLY
ts-012 Prefer for-of and array methods over index loops Idioms 4 ZEN-RIGHT-ABSTRACTION, ZEN-FAIL-FAST
ts-013 Prefer async/await over raw promise chains Async 6 ZEN-FAIL-FAST, ZEN-RETURN-EARLY
ts-014 Prefer named exports over default exports Organization 4 ZEN-STRICT-FENCES, ZEN-UNAMBIGUOUS-NAME
ts-015 Avoid catch-all types like Object or {} Type Safety 6 ZEN-EXPLICIT-INTENT
ts-016 Avoid console usage in production code Clarity 4 ZEN-EXPLICIT-INTENT, ZEN-FAIL-FAST
ts-017 Use ES module imports instead of require() Idioms 5 ZEN-RIGHT-ABSTRACTION
ts-018 Use template literals instead of string concatenation Readability 3 ZEN-UNAMBIGUOUS-NAME, ZEN-FAIL-FAST
ts-001 — Avoid 'any' type

Use proper types instead of any to maintain type safety

Universal Dogmas: ZEN-EXPLICIT-INTENT Common Violations:

  • Explicit any annotations
  • Implicit any from missing types
  • Type assertions to any
  • any[] arrays

Detectable Patterns:

  • : any
  • as any

Thresholds:

Parameter Default
max_any_usages 0
detect_explicit_any True
detect_assertions_any True
detect_any_arrays True

Recommended Fix

unknown, specific types, or generics

ts-002 — Use strict mode

Enable strict TypeScript compiler options

Universal Dogmas: ZEN-EXPLICIT-INTENT Common Violations:

  • strict: false in tsconfig
  • Disabled strictNullChecks
  • Disabled noImplicitAny

Thresholds:

Parameter Default
require_strict True
require_no_implicit_any True
require_strict_null_checks True
ts-003 — Prefer interfaces over type aliases for objects

Use interfaces for object shapes, types for unions/primitives

Universal Dogmas: ZEN-RIGHT-ABSTRACTION, ZEN-UNAMBIGUOUS-NAME, ZEN-PROPORTIONATE-COMPLEXITY Common Violations:

  • Type aliases for simple object shapes
  • Not using interface extension

Detectable Patterns:

  • type ObjectShape = { ... }

Thresholds:

Parameter Default
max_object_type_aliases 0
ts-004 — Always specify return types

Explicit return types improve readability and catch errors

Universal Dogmas: ZEN-EXPLICIT-INTENT, ZEN-FAIL-FAST Common Violations:

  • Public functions without return type
  • Exported functions without return type
  • Callbacks without return type

Thresholds:

Parameter Default
require_return_types True
ts-005 — Use readonly when appropriate

Mark immutable properties as readonly

Universal Dogmas: ZEN-VISIBLE-STATE Common Violations:

  • Properties that should be readonly
  • Arrays that should be ReadonlyArray
  • Mutable config objects

Thresholds:

Parameter Default
require_readonly_properties True
min_readonly_occurrences 1
ts-006 — Leverage type guards

Use type guards for runtime type checking

Universal Dogmas: ZEN-EXPLICIT-INTENT Common Violations:

  • Type assertions without validation
  • Not narrowing union types
  • Using 'as' instead of type guards

Thresholds:

Parameter Default
max_type_assertions 0

Recommended Fix

User-defined type guards (is predicates)

ts-007 — Use utility types

Leverage built-in utility types (Partial, Pick, Omit, etc.)

Universal Dogmas: ZEN-RIGHT-ABSTRACTION Common Violations:

  • Manual type transformations
  • Duplicated type definitions
  • Not using Partial for optional updates

Thresholds:

Parameter Default
min_utility_type_usage 1
min_object_type_aliases 2
ts-008 — Avoid non-null assertions

Handle null/undefined properly instead of using !

Universal Dogmas: ZEN-EXPLICIT-INTENT Common Violations:

  • Excessive use of ! operator
  • Non-null assertions without validation
  • Chained non-null assertions

Detectable Patterns:

  • variable!
  • ?.!

Thresholds:

Parameter Default
max_non_null_assertions 0
ts-009 — Use enums or const assertions appropriately

Use const enums or const assertions for constant values

Universal Dogmas: ZEN-RIGHT-ABSTRACTION Common Violations:

  • Plain objects for enumerations
  • String literal unions without const assertion
  • Regular enums that should be const

Thresholds:

Parameter Default
max_plain_enum_objects 0
ts-010 — Prefer unknown over any for uncertain types

Use unknown when type is truly unknown, forces type checking

Universal Dogmas: ZEN-EXPLICIT-INTENT, ZEN-FAIL-FAST Common Violations:

  • Using any for API responses
  • Using any for error types
  • any for third-party data

Thresholds:

Parameter Default
max_any_for_unknown 0
ts-011 — Use optional chaining instead of manual null checks

Optional chaining (?.) simplifies nested property access and avoids verbose guard clauses

Universal Dogmas: ZEN-RIGHT-ABSTRACTION, ZEN-RETURN-EARLY Common Violations:

  • Manual && chains for nested access
  • Verbose null/undefined checks before property access
  • Nested ternaries for safe property access

Thresholds:

Parameter Default
max_manual_null_checks 0
ts-012 — Prefer for-of and array methods over index loops

Modern iteration is more readable and less error-prone than C-style for loops

Universal Dogmas: ZEN-RIGHT-ABSTRACTION, ZEN-FAIL-FAST Common Violations:

  • Using for(let i=0; ...) when for-of suffices
  • Index-based iteration over arrays
  • Manual length-based loops

Thresholds:

Parameter Default
max_index_loops 0
ts-013 — Prefer async/await over raw promise chains

async/await produces flatter, more readable asynchronous code than .then() chains

Universal Dogmas: ZEN-FAIL-FAST, ZEN-RETURN-EARLY Common Violations:

  • Using .then() chains instead of await
  • Nested .then() callbacks
  • Mixing .then() and async/await styles

Thresholds:

Parameter Default
max_promise_chains 0
ts-014 — Prefer named exports over default exports

Named exports improve refactoring support and IDE auto-imports

Universal Dogmas: ZEN-STRICT-FENCES, ZEN-UNAMBIGUOUS-NAME Common Violations:

  • Using export default for modules
  • Default-exporting classes or functions
  • Inconsistent export styles in a project

Thresholds:

Parameter Default
max_default_exports 0
ts-015 — Avoid catch-all types like Object or {}

Catch-all types bypass the type system; use precise types or Record instead

Universal Dogmas: ZEN-EXPLICIT-INTENT Common Violations:

  • Typing as Object or object
  • Using {} as a type annotation
  • Overly broad type parameters

Thresholds:

Parameter Default
max_catch_all_types 0
ts-016 — Avoid console usage in production code

Use a structured logging framework instead of console.log for production code

Universal Dogmas: ZEN-EXPLICIT-INTENT, ZEN-FAIL-FAST Common Violations:

  • console.log for debugging left in code
  • console.error instead of proper error handling
  • console.warn without structured logging

Thresholds:

Parameter Default
max_console_usages 0
ts-017 — Use ES module imports instead of require()

ES module syntax enables tree-shaking and static analysis

Universal Dogmas: ZEN-RIGHT-ABSTRACTION Common Violations:

  • Using require() in TypeScript files
  • Mixing require and import styles
  • CommonJS patterns in modern TypeScript

Thresholds:

Parameter Default
max_require_calls 0
ts-018 — Use template literals instead of string concatenation

Template literals are more readable and less error-prone than + concatenation

Universal Dogmas: ZEN-UNAMBIGUOUS-NAME, ZEN-FAIL-FAST Common Violations:

  • String concatenation with + operator
  • Multi-part string building with +
  • Variable interpolation via concatenation

Thresholds:

Parameter Default
max_string_concats 0

Detector Catalog

Async

Detector What It Catches Rule IDs
TsAsyncAwaitDetector Detects raw .then() promise chains encouraging async/await usage ts-013
TsPromiseChainDetector Detects raw .then() promise chains replaceable by async/await ts-013

Clarity

Detector What It Catches Rule IDs
TsConsoleUsageDetector Detects console.* calls in TypeScript production code ts-016
TsNoConsoleDetector Detects console.* calls in production code ts-016

Configuration

Detector What It Catches Rule IDs
TsStrictModeDetector Checks whether strict compiler options are enabled in the project ts-002

Idioms

Detector What It Catches Rule IDs
TsEnumConstDetector Detects plain object literals used as constants instead of enums or as const ts-009
TsForOfDetector Detects C-style index-based for loops encouraging for...of iteration ts-012
TsImportOrderDetector Detects CommonJS require() calls mixed with ES module imports ts-017
TsIndexLoopDetector Detects C-style index-based for loops replaceable by for-of or array methods ts-012
TsInterfacePreferenceDetector Flags object-shaped type aliases that should be interfaces instead ts-003
TsOptionalChainingDetector Detects manual null-check chains replaceable by optional chaining (?.) ts-011
TsRequireImportDetector Detects require() calls encouraging ES module imports instead ts-017
TsUtilityTypesDetector Detects missed opportunities to use built-in utility types like Partial or Pick ts-007

Immutability

Detector What It Catches Rule IDs
TsReadonlyDetector Detects insufficient use of readonly for immutable properties and arrays ts-005

Organization

Detector What It Catches Rule IDs
TsDefaultExportDetector Detects export default statements encouraging named exports instead ts-014
TsNamedExportDetector Detects export default usages encouraging named exports ts-014

Readability

Detector What It Catches Rule IDs
TsStringConcatDetector Detects string concatenation patterns encouraging template literals ts-018
TsTemplateLiteralDetector Detects string concatenation patterns encouraging template literals ts-018

Type Safety

Detector What It Catches Rule IDs
TsAnyUsageDetector Detects excessive use of the any type that undermines TypeScript's value ts-001
TsCatchAllTypeDetector Detects catch-all type annotations (Object, object, {}) ts-015
TsNonNullAssertionDetector Flags excessive non-null assertion operators (!) that silence null safety ts-008
TsObjectTypeDetector Detects generic Object/object/{} type annotations ts-015
TsReturnTypeDetector Flags exported functions that lack explicit return type annotations ts-004
TsTypeGuardDetector Flags overuse of type assertions (as T) instead of user-defined type guards ts-006
TsUnknownOverAnyDetector Flags codebases that use any without ever using the safer unknown alternative ts-010
Principle → Detector Wiring
%%{init: {"theme": "base", "flowchart": {"useMaxWidth": false, "htmlLabels": true, "nodeSpacing": 40, "rankSpacing": 60}}}%%
graph TD
ts_001["ts-001<br/>Avoid &#x27;any&#x27; type"]
ts_002["ts-002<br/>Use strict mode"]
ts_003["ts-003<br/>Prefer interfaces over ty..."]
ts_004["ts-004<br/>Always specify return typ..."]
ts_005["ts-005<br/>Use readonly when appropr..."]
ts_006["ts-006<br/>Leverage type guards"]
ts_007["ts-007<br/>Use utility types"]
ts_008["ts-008<br/>Avoid non-null assertions"]
ts_009["ts-009<br/>Use enums or const assert..."]
ts_010["ts-010<br/>Prefer unknown over any f..."]
ts_011["ts-011<br/>Use optional chaining ins..."]
ts_012["ts-012<br/>Prefer for-of and array m..."]
ts_013["ts-013<br/>Prefer async/await over r..."]
ts_014["ts-014<br/>Prefer named exports over..."]
ts_015["ts-015<br/>Avoid catch-all types lik..."]
ts_016["ts-016<br/>Avoid console usage in pr..."]
ts_017["ts-017<br/>Use ES module imports ins..."]
ts_018["ts-018<br/>Use template literals ins..."]
det_TsAnyUsageDetector["Ts Any<br/>Usage"]
ts_001 --> det_TsAnyUsageDetector
det_TsAsyncAwaitDetector["Ts Async<br/>Await"]
ts_013 --> det_TsAsyncAwaitDetector
det_TsCatchAllTypeDetector["Ts Catch<br/>All Type"]
ts_015 --> det_TsCatchAllTypeDetector
det_TsConsoleUsageDetector["Ts Console<br/>Usage"]
ts_016 --> det_TsConsoleUsageDetector
det_TsDefaultExportDetector["Ts Default<br/>Export"]
ts_014 --> det_TsDefaultExportDetector
det_TsEnumConstDetector["Ts Enum<br/>Const"]
ts_009 --> det_TsEnumConstDetector
det_TsForOfDetector["Ts For<br/>Of"]
ts_012 --> det_TsForOfDetector
det_TsImportOrderDetector["Ts Import<br/>Order"]
ts_017 --> det_TsImportOrderDetector
det_TsIndexLoopDetector["Ts Index<br/>Loop"]
ts_012 --> det_TsIndexLoopDetector
det_TsInterfacePreferenceDetector["Ts Interface<br/>Preference"]
ts_003 --> det_TsInterfacePreferenceDetector
det_TsNamedExportDetector["Ts Named<br/>Export"]
ts_014 --> det_TsNamedExportDetector
det_TsNoConsoleDetector["Ts No<br/>Console"]
ts_016 --> det_TsNoConsoleDetector
det_TsNonNullAssertionDetector["Ts Non<br/>Null Assertion"]
ts_008 --> det_TsNonNullAssertionDetector
det_TsObjectTypeDetector["Ts Object<br/>Type"]
ts_015 --> det_TsObjectTypeDetector
det_TsOptionalChainingDetector["Ts Optional<br/>Chaining"]
ts_011 --> det_TsOptionalChainingDetector
det_TsPromiseChainDetector["Ts Promise<br/>Chain"]
ts_013 --> det_TsPromiseChainDetector
det_TsReadonlyDetector["Ts Readonly"]
ts_005 --> det_TsReadonlyDetector
det_TsRequireImportDetector["Ts Require<br/>Import"]
ts_017 --> det_TsRequireImportDetector
det_TsReturnTypeDetector["Ts Return<br/>Type"]
ts_004 --> det_TsReturnTypeDetector
det_TsStrictModeDetector["Ts Strict<br/>Mode"]
ts_002 --> det_TsStrictModeDetector
det_TsStringConcatDetector["Ts String<br/>Concat"]
ts_018 --> det_TsStringConcatDetector
det_TsTemplateLiteralDetector["Ts Template<br/>Literal"]
ts_018 --> det_TsTemplateLiteralDetector
det_TsTypeGuardDetector["Ts Type<br/>Guard"]
ts_006 --> det_TsTypeGuardDetector
det_TsUnknownOverAnyDetector["Ts Unknown<br/>Over Any"]
ts_010 --> det_TsUnknownOverAnyDetector
det_TsUtilityTypesDetector["Ts Utility<br/>Types"]
ts_007 --> det_TsUtilityTypesDetector
Detector Class Hierarchy
%%{init: {"theme": "base"}}%%
classDiagram
    direction TB
    class ViolationDetector {
        <<abstract>>
        +detect(context, config)
    }
    class det_01["Ts Any Usage"]
    ViolationDetector <|-- det_01
    class det_02["Ts Async Await"]
    ViolationDetector <|-- det_02
    class det_03["Ts Catch All Type"]
    ViolationDetector <|-- det_03
    class det_04["Ts Console Usage"]
    ViolationDetector <|-- det_04
    class det_05["Ts Default Export"]
    ViolationDetector <|-- det_05
    class det_06["Ts Enum Const"]
    ViolationDetector <|-- det_06
    class det_07["Ts For Of"]
    ViolationDetector <|-- det_07
    class det_08["Ts Import Order"]
    ViolationDetector <|-- det_08
    class det_09["Ts Index Loop"]
    ViolationDetector <|-- det_09
    class det_10["Ts Interface Preference"]
    ViolationDetector <|-- det_10
    class det_11["Ts Named Export"]
    ViolationDetector <|-- det_11
    class det_12["Ts No Console"]
    ViolationDetector <|-- det_12
    class det_13["Ts Non Null Assertion"]
    ViolationDetector <|-- det_13
    class det_14["Ts Object Type"]
    ViolationDetector <|-- det_14
    class det_15["Ts Optional Chaining"]
    ViolationDetector <|-- det_15
    class det_16["Ts Promise Chain"]
    ViolationDetector <|-- det_16
    class det_17["Ts Readonly"]
    ViolationDetector <|-- det_17
    class det_18["Ts Require Import"]
    ViolationDetector <|-- det_18
    class det_19["Ts Return Type"]
    ViolationDetector <|-- det_19
    class det_20["Ts Strict Mode"]
    ViolationDetector <|-- det_20
    class det_21["Ts String Concat"]
    ViolationDetector <|-- det_21
    class det_22["Ts Template Literal"]
    ViolationDetector <|-- det_22
    class det_23["Ts Type Guard"]
    ViolationDetector <|-- det_23
    class det_24["Ts Unknown Over Any"]
    ViolationDetector <|-- det_24
    class det_25["Ts Utility Types"]
    ViolationDetector <|-- det_25
Analysis Pipeline
%%{init: {"theme": "base", "flowchart": {"useMaxWidth": false, "htmlLabels": true, "nodeSpacing": 50, "rankSpacing": 70}}}%%
flowchart TD
Source(["Source Code"]) --> Parse["Parse & Tokenize"]
Parse --> Metrics["Compute Metrics"]
Metrics --> Pipeline{"25 Detectors"}
Pipeline --> Collect["Aggregate Violations"]
Collect --> Result(["AnalysisResult<br/>18 principles"])
Analysis States
%%{init: {"theme": "base"}}%%
stateDiagram-v2
    [*] --> Ready
    Ready --> Parsing : analyze(code)
    Parsing --> Computing : AST ready
    Computing --> Detecting : metrics ready
    Detecting --> Reporting : 25 detectors run
    Reporting --> [*] : AnalysisResult
    Parsing --> Reporting : parse error (best-effort)

Configuration

languages:
  typescript:
    enabled: true
    pipeline:
      - type: ts_any_usage
        max_any_usages: 0
        detect_explicit_any: True
        detect_assertions_any: True
        detect_any_arrays: True
      - type: ts_async_await
        max_promise_chains: 2
        max_then_chains: 0
      - type: ts_catch_all_types
        max_catch_all_types: 0
      - type: ts_console_usage
        max_console_usages: 0
      - type: ts_default_exports
        max_default_exports: 0
      - type: ts_enum_const
        max_plain_enum_objects: 0
      - type: ts_for_of
        max_index_loops: 0
        max_index_based_loops: 0
      - type: ts_import_order
        max_require_calls: 0
        max_require_usages: 0
      - type: ts_index_loops
        max_index_loops: 0
      - type: ts_interface_preference
        max_object_type_aliases: 0
      - type: ts_named_export
        max_default_exports: 0
        max_default_export_usages: 0
      - type: ts_no_console
        max_console_usages: 0
        max_console_statements: 0
      - type: ts_non_null_assertions
        max_non_null_assertions: 0
      - type: ts_object_type
        max_catch_all_types: 0
        max_object_types: 0
      - type: ts_optional_chaining
        max_manual_null_checks: 0
      - type: ts_promise_chains
        max_promise_chains: 0
      - type: ts_readonly
        require_readonly_properties: True
        min_readonly_occurrences: 1
      - type: ts_require_imports
        max_require_calls: 0
      - type: ts_return_types
        require_return_types: True
      - type: ts_strict_mode
        require_strict: True
        require_no_implicit_any: True
        require_strict_null_checks: True
      - type: ts_string_concats
        max_string_concats: 0
      - type: ts_template_literal
        max_string_concats: 3
        max_string_concatenations: 0
      - type: ts_type_guards
        max_type_assertions: 0
      - type: ts_unknown_over_any
        max_any_for_unknown: 0
      - type: ts_utility_types
        min_utility_type_usage: 1
        min_object_type_aliases: 2
Migrating from JavaScript?

Start with max_any_count: 10 and lower it sprint by sprint. Use the ts-010 detector to find any that should be unknown first — those are the safest to fix.

See Also