Smithery Logo
MCPsSkillsDocsPricing
Login
Smithery Logo

Give agents more agency

Resources

DocumentationPrivacy PolicySystem Status

Company

PricingAboutBlog

Connect

© 2026 Smithery. All rights reserved.

    djankies

    validating-type-assertions

    djankies/validating-type-assertions
    Coding

    About

    SKILL.md

    Install

    Install via Skills CLI

    or add to your agent
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    ├─
    ├─
    └─

    About

    Teaches when type assertions are safe versus dangerous in TypeScript...

    SKILL.md

    This skill teaches the difference between safe and dangerous type assertions, preventing the common anti-pattern of using `as Type` on unvalidated external data. Based on stress test findings where 50% of agents misused type assertions. This skill activates when:
    • Code contains as keyword or angle bracket syntax <Type>
    • Working with type assertions or type casting
    • Converting between types
    • User mentions type assertions, casting, or "as" keyword
    • Code uses assertions on external data
    **Critical Distinction**:
    • Type Guard: Runtime check that narrows types safely
    • Type Assertion: Compile-time instruction telling TypeScript to trust you

    Type assertions are TypeScript compiler directives, not runtime operations.

    const data = JSON.parse(json) as User;
    

    This compiles fine but provides ZERO runtime safety. If JSON is malformed, your code crashes.

    Rule: Type assertions are safe only when YOU control the data or have already validated it.

    ## Assertion Safety Decision Tree

    Question 1: Where does this data come from?

    • From your own code (constants, constructors) → Assertion OK
    • From external source (API, user input, JSON) → NEVER assert, validate instead

    Question 2: Have you validated the data?

    • Yes, with runtime validation → Assertion OK after validation
    • No validation → NEVER assert

    Question 3: Is this a TypeScript limitation?

    • Yes (const assertions, narrowing limitations) → Assertion OK
    • No (trying to skip validation) → NEVER assert
    ## Example 1: Dangerous Assertions (DO NOT DO)

    ❌ Asserting external API data

    async function fetchUser(id: string): Promise<User> {
      const response = await fetch(`/api/users/${id}`);
      const data = await response.json() as User;
      return data;
    }
    

    Problem: If API returns different structure, runtime crash. TypeScript provides no protection.

    ✅ Validate instead

    async function fetchUser(id: string): Promise<User> {
      const response = await fetch(`/api/users/${id}`);
      const data: unknown = await response.json();
    
      if (!isUser(data)) {
        throw new Error("Invalid user data from API");
      }
    
      return data;
    }
    

    ❌ Asserting JSON.parse result

    const config = JSON.parse(configString) as Config;
    

    Problem: If JSON is malformed or wrong shape, crash at runtime.

    ✅ Validate with Zod

    const data: unknown = JSON.parse(configString);
    const config = ConfigSchema.parse(data);
    

    ❌ Asserting user input

    function handleSubmit(formData: FormData) {
      const user = {
        name: formData.get("name"),
        email: formData.get("email")
      } as User;
    
      saveUser(user);
    }
    

    Problem: FormData can contain anything. No validation.

    ✅ Validate form data

    function handleSubmit(formData: FormData) {
      const data = {
        name: formData.get("name"),
        email: formData.get("email")
      };
    
      const user = UserSchema.parse(data);
      saveUser(user);
    }
    

    Example 2: Safe Assertions (OK to use)

    ✅ Const assertions

    const routes = [
      { path: "/", component: "Home" },
      { path: "/about", component: "About" }
    ] as const;
    
    type Route = typeof routes[number];
    

    Safe because: Data is hardcoded, not external.


    ✅ After validation

    async function fetchUser(id: string): Promise<User> {
      const response = await fetch(`/api/users/${id}`);
      const data: unknown = await response.json();
    
      const result = UserSchema.safeParse(data);
      if (!result.success) {
        throw new Error("Invalid user data");
      }
    
      return result.data as User;
    }
    

    Safe because: Data validated before assertion. (Though result.data already has correct type, so assertion is redundant.)


    ✅ Constructor results

    class User {
      constructor(
        public id: string,
        public name: string
      ) {}
    }
    
    const users = [
      new User("1", "Alice"),
      new User("2", "Bob")
    ] as User[];
    

    Safe because: You control construction, types are guaranteed.


    ✅ Type narrowing limitations

    interface Circle { kind: "circle"; radius: number; }
    interface Square { kind: "square"; size: number; }
    type Shape = Circle | Square;
    
    function getArea(shape: Shape): number {
      if (shape.kind === "circle") {
        return Math.PI * shape.radius ** 2;
      }
      return shape.size ** 2;
    }
    

    Safe because: TypeScript narrows to Square after checking for circle. Use else to avoid assertion.


    ✅ Type widening prevention

    const config = {
      apiUrl: "https://api.example.com",
      timeout: 5000
    } as const;
    

    Safe because: Preventing literal types from widening to general types.


    ✅ Unknown to specific after validation

    function processError(error: unknown): string {
      if (error instanceof Error) return error.message;
      if (typeof error === "string") return error;
      return String(error);
    }
    

    Safe because: Type guards narrow before use without assertions.


    Example 3: Double Assertion Anti-Pattern

    ❌ Double assertion to bypass safety

    const value = "not a number" as unknown as number;
    

    Problem: Intentionally bypassing type system. Defeats TypeScript's purpose.

    ✅ Fix the types properly

    const value: unknown = "not a number";
    
    if (typeof value === "number") {
      console.log(value.toFixed(2));
    }
    

    Example 4: Non-null Assertion

    ❌ Non-null assertion on external data

    const user = await fetchUser(id);
    console.log(user!.name);
    

    Problem: If fetchUser can return null, this crashes.

    ✅ Check explicitly

    const user = await fetchUser(id);
    
    if (user) {
      console.log(user.name);
    } else {
      console.log("User not found");
    }
    

    ✅ Non-null assertion after explicit check

    const element = document.getElementById("root");
    
    if (!element) {
      throw new Error("Root element not found");
    }
    
    element.appendChild(child);
    

    Safe because: Checked for null and threw. TypeScript narrows automatically, no assertion needed.


    Example 5: Assertion Functions vs Assertions

    ❌ Assertion to avoid validation

    function getUser(data: unknown): User {
      return data as User;
    }
    

    ✅ Assertion function with validation

    function assertIsUser(data: unknown): asserts data is User {
      if (!isUser(data)) {
        throw new Error("Invalid user data");
      }
    }
    
    function getUser(data: unknown): User {
      assertIsUser(data);
      return data;
    }
    
    ## Reference Files

    For related patterns:

    • Runtime Validation: Use the using-runtime-checks skill for proper validation with Zod
    • Type Guards: Use the using-type-guards skill for safe type narrowing
    • Unknown Type: Use the avoiding-any-types skill for handling unknown data safely
    **MUST:**
    • Validate external data with type guards or validation libraries
    • Use assertion functions (asserts value is Type) over direct assertions
    • Check for null/undefined before non-null assertions (!)
    • Document WHY assertion is safe when used

    SHOULD:

    • Prefer type guards over assertions
    • Use as const for literal type inference
    • Limit assertions to known-safe scenarios
    • Consider if assertion indicates missing validation

    NEVER:

    • Assert on external data without validation (APIs, JSON, user input)
    • Use double assertions (as unknown as Type)
    • Use non-null assertion (!) without prior check
    • Assert to silence compiler errors (fix the types instead)
    • Trust that data "will be correct"
    ## When Assertions Are Safe

    Type assertion is safe when ALL of these are true:

    • Data source is internal/controlled (not external)
    • OR data has been validated with runtime checks
    • You understand what the assertion does (compiler directive, not runtime check)
    • Assertion is documented with reason
    • No double assertions being used

    If ANY checkbox is false, use validation instead.

    ## Pattern Library

    Pattern 1: Validated Assertion

    function parseUser(data: unknown): User {
      const result = UserSchema.safeParse(data);
    
      if (!result.success) {
        throw new ValidationError("Invalid user", result.error);
      }
    
      return result.data;
    }
    

    Pattern 2: Const Assertion for Config

    const API_ENDPOINTS = {
      users: "/api/users",
      posts: "/api/posts",
      comments: "/api/comments"
    } as const;
    
    type Endpoint = typeof API_ENDPOINTS[keyof typeof API_ENDPOINTS];
    

    Pattern 3: Assertion Function

    function assertNever(value: never): never {
      throw new Error(`Unexpected value: ${value}`);
    }
    
    function handleShape(shape: Shape) {
      switch (shape.kind) {
        case "circle":
          return Math.PI * shape.radius ** 2;
        case "square":
          return shape.size ** 2;
        default:
          assertNever(shape);
      }
    }
    

    Pattern 4: Type Predicate Instead of Assertion

    function isDefined<T>(value: T | null | undefined): value is T {
      return value !== null && value !== undefined;
    }
    
    const values = [1, null, 2, undefined, 3];
    const defined = values.filter(isDefined);
    
    ## Removing Unsafe Assertions

    Find assertions: grep -rn " as " src/ and grep -rn "!" src/ | grep -v "!=="

    Classify each: External data → add validation; After validation → verify; Const assertion → keep; Bypassing types → fix types

    Replace pattern:

    const data = JSON.parse(json) as User;
    

    Becomes:

    const data: unknown = JSON.parse(json);
    const user = UserSchema.parse(data);
    

    Enable strict mode: Set "strict": true and "noImplicitAny": true in tsconfig.json

    Recommended Servers
    URL Safety Validator MCP
    URL Safety Validator MCP
    vastlint - IAB XML VAST validator and linter
    vastlint - IAB XML VAST validator and linter
    VAT Validator MCP
    VAT Validator MCP
    Repository
    djankies/claude-configs
    Files