🎯

code-gen-independent

🎯Skill

from marius-townhouse/effective-typescript-skills

VibeIndex|
What it does

Generates JavaScript code despite TypeScript type errors and demonstrates that TypeScript types are erased at runtime, requiring alternative type checking strategies.

πŸ“¦

Part of

marius-townhouse/effective-typescript-skills(83 items)

code-gen-independent

Installation

Quick InstallInstall with npx
npx skills add marius-townhouse/effective-typescript-skills --all
Quick InstallInstall with npx
npx skills add marius-townhouse/effective-typescript-skills -s prefer-unknown-over-any exhaustiveness-checking
Quick InstallInstall with npx
npx skills add marius-townhouse/effective-typescript-skills -a opencode claude-code
Quick InstallInstall with npx
npx skills add marius-townhouse/effective-typescript-skills -l
git cloneClone repository
git clone https://github.com/marius-townhouse/effective-typescript-skills.git
πŸ“– Extracted from docs: marius-townhouse/effective-typescript-skills
1Installs
-
AddedFeb 4, 2026

Skill Details

SKILL.md

Use when confused about types at runtime. Use when trying to use instanceof with interfaces. Use when type errors don't prevent JavaScript output.

Overview

# Understand That Code Generation Is Independent of Types

Overview

TypeScript compilation and type checking are separate processes.

The TypeScript compiler does two things: (1) transpile TypeScript to JavaScript, and (2) check types. These are independent - type errors don't prevent code generation, and types don't exist at runtime.

When to Use This Skill

  • Confused why code runs despite type errors
  • Trying to check types at runtime
  • Using instanceof with interfaces
  • Expecting types to affect runtime behavior

The Iron Rule

```

NEVER expect TypeScript types to exist at runtime. They are erased.

```

Key Facts:

  • Code with type errors can still produce JavaScript output
  • Types are erased during compilation
  • You can't use instanceof on TypeScript interfaces
  • Runtime checks require JavaScript constructs

Type Errors Don't Prevent Output

```bash

$ cat test.ts

let x = 'hello';

x = 1234; // Type error!

$ tsc test.ts

test.ts:2:1 - error TS2322: Type 'number' is not assignable to type 'string'

$ cat test.js

var x = 'hello';

x = 1234; // JavaScript was still generated!

```

Type errors are like warnings - they don't stop compilation.

You Can't Check Types at Runtime

```typescript

interface Square {

width: number;

}

interface Rectangle extends Square {

height: number;

}

type Shape = Square | Rectangle;

function calculateArea(shape: Shape) {

if (shape instanceof Rectangle) {

// ~~~~~~~~~ 'Rectangle' only refers to a type,

// but is being used as a value here

return shape.width * shape.height;

}

return shape.width * shape.width;

}

```

Why? interface and type are erased. They don't exist in JavaScript.

Solutions for Runtime Type Checking

Option 1: Property Checking

```typescript

function calculateArea(shape: Shape) {

if ('height' in shape) {

// TypeScript knows shape is Rectangle here

return shape.width * shape.height;

}

return shape.width * shape.width;

}

```

Option 2: Tagged Union (Recommended)

```typescript

interface Square {

kind: 'square';

width: number;

}

interface Rectangle {

kind: 'rectangle';

width: number;

height: number;

}

type Shape = Square | Rectangle;

function calculateArea(shape: Shape) {

if (shape.kind === 'rectangle') {

return shape.width * shape.height;

}

return shape.width * shape.width;

}

```

Option 3: Use Classes

```typescript

class Square {

constructor(public width: number) {}

}

class Rectangle extends Square {

constructor(width: number, public height: number) {

super(width);

}

}

function calculateArea(shape: Square | Rectangle) {

if (shape instanceof Rectangle) {

// This works! Classes exist at runtime

return shape.width * shape.height;

}

return shape.width * shape.width;

}

```

Type Operations Don't Affect Runtime

```typescript

function asNumber(val: number | string): number {

return val as number; // Type assertion

}

// Generated JavaScript:

function asNumber(val) {

return val; // No conversion! Just returns val as-is

}

```

Type assertions don't convert values. Use runtime code:

```typescript

function asNumber(val: number | string): number {

return typeof val === 'string' ? Number(val) : val;

}

```

Runtime Types May Differ from Declared Types

```typescript

function setLightSwitch(value: boolean) {

switch (value) {

case true: turnLightOn(); break;

case false: turnLightOff(); break;

default:

console.log("I'm afraid I can't do that.");

// TypeScript thinks this is unreachable, but...

}

}

// At runtime, someone could call:

setLightSwitch("ON" as any); // Hits the default case!

```

API responses, external data, and any types can cause runtime type mismatches.

You Can't Overload Based on Types

```typescript

// ❌ This doesn't work - types are erased

function add(a: number, b: number) { return a + b; }

function add(a: string, b: string) { return a + b; }

// ~~~ Duplicate function implementation

// βœ… Use a single implementation with union type

function add(a: number | string, b: number | string) {

if (typeof a === 'number' && typeof b === 'number') {

return a + b;

}

return String(a) + String(b);

}

```

Pressure Resistance Protocol

1. "Just Use `as Type`"

Pressure: "Type assertion will convert the value"

Response: Assertions don't convert. They're compile-time only.

Action: Write actual runtime conversion code.

2. "Use instanceof"

Pressure: "instanceof should work on my interface"

Response: Interfaces don't exist at runtime. Use tagged unions or classes.

Action: Add a discriminant property or use classes.

Red Flags - STOP and Reconsider

  • Using instanceof with interface/type
  • Expecting type assertions to convert values
  • Assuming type errors prevent JavaScript output
  • Relying on TypeScript types for runtime validation

Quick Reference

| TypeScript Construct | Exists at Runtime? |

|---------------------|-------------------|

| interface | No |

| type | No |

| Type annotation (: T) | No |

| Type assertion (as T) | No |

| class | Yes |

| enum (non-const) | Yes |

| Tagged union property | Yes |

The Bottom Line

Types are erased. Code generation is independent of type checking.

TypeScript types exist only at compile time. For runtime type checking, use JavaScript constructs: property checks, tagged unions, classes, or typeof/instanceof (for values, not types).

Reference

Based on "Effective TypeScript" by Dan Vanderkam, Item 3: Understand That Code Generation Is Independent of Types.

More from this repository10

🎯
tsdoc-comments🎯Skill

Generates TypeScript documentation comments (TSDoc) to explain public APIs, complex types, and provide comprehensive code documentation with IDE tooltips.

🎯
async-over-callbacks🎯Skill

Transforms callback-based asynchronous code into clean, readable async/await patterns for better type flow and error handling.

🎯
context-type-inference🎯Skill

Helps restore precise type context when extracting values, preventing type inference errors through annotations, const assertions, and type preservation techniques.

🎯
module-by-module-migration🎯Skill

Guides developers through systematic TypeScript module migration, breaking down complex refactoring into manageable, incremental steps.

🎯
ts-js-relationship🎯Skill

Explains TypeScript's relationship to JavaScript, highlighting how it adds static typing and catches errors before runtime while remaining fully compatible with JavaScript code.

🎯
type-safe-monkey-patching🎯Skill

Enables type-safe runtime extension of global objects and DOM elements in TypeScript without sacrificing type checking or using `as any`.

🎯
create-objects-all-at-once🎯Skill

Efficiently initializes multiple TypeScript objects simultaneously using concise object literal syntax and spread operators.

🎯
precise-string-types🎯Skill

Enforces strict string type constraints and prevents unintended string type conversions in TypeScript projects.

🎯
variadic-tuple-types🎯Skill

Demonstrates advanced TypeScript tuple type techniques for creating flexible function signatures with varying argument lengths and types.

🎯
type-display-attention🎯Skill

Displays and simplifies complex TypeScript types to improve IDE readability and developer experience.