Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
YouTube Security VideosAnonymous Official: I'm begging you to understand this..(20.09.2026 um 21:30 Uhr)
Sichere ProgrammierungHow to Monitor Cron Jobs with a Simple HTTP Health Check(20.09.2026 um 23:14 Uhr)
Sichere ProgrammierungWhy my builds don't run on my laptop(20.09.2026 um 23:15 Uhr)
Sichere ProgrammierungDesigning offline-first when there's no server(20.09.2026 um 23:16 Uhr)
Sichere ProgrammierungSearching for Better Game Recommendations with Jev(20.09.2026 um 23:19 Uhr)
Linux Tipps & HardeningUbuntu 26.10 stops low memory from killing your desktop session(20.09.2026 um 19:55 Uhr)
YouTube Security VideosAnonymous Official: I'm begging you to understand this..(20.09.2026 um 21:30 Uhr)
Sichere ProgrammierungHow to Monitor Cron Jobs with a Simple HTTP Health Check(20.09.2026 um 23:14 Uhr)
Sichere ProgrammierungWhy my builds don't run on my laptop(20.09.2026 um 23:15 Uhr)
Sichere ProgrammierungDesigning offline-first when there's no server(20.09.2026 um 23:16 Uhr)
Sichere ProgrammierungSearching for Better Game Recommendations with Jev(20.09.2026 um 23:19 Uhr)
Linux Tipps & HardeningUbuntu 26.10 stops low memory from killing your desktop session(20.09.2026 um 19:55 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

TypeScript Strict Mode in Practice: Catching Bugs with Type Safety

Reagiere als Erste:r — dein Feedback zählt!

This article is part of the and Design Advent Calendar 2025 (Day 18).

Yesterday I wrote about "Semantic Search." Today, I'll share my experience introducing TypeScript's strict mode to an existing project.

Why I Introduced Strict Mode

Even with TypeScript, runtime errors still occur.

Cannot read property 'name' of null
undefined is not a function

When these errors started piling up, I investigated and found a common pattern. They were happening in places where type checking was too lenient.

TypeScript uses lenient settings by default. Without enabling strict mode, many problems slip through undetected.

Options I Enabled

{
  "compilerOptions": {
    "strict": false,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "noUnusedLocals": false,
    "noUnusedParameters": false
  }
}

noImplicitAny

Parameters without type annotations implicitly become any type. Since any allows any operation, type checking becomes ineffective.

// With noImplicitAny: false
function double(value) {  // value is any type
  return value * 2;
}

double("hello");  // Compiles fine, but result is NaN

With noImplicitAny: true, parameters without type annotations cause errors. You can immediately spot "places where you forgot to write types."

strictNullChecks

Without this option, all types implicitly include null and undefined.

// With strictNullChecks: false
const user: User = getUser();  // Might return null
console.log(user.name);  // Could crash at runtime

With strictNullChecks: true, functions that might return null must explicitly declare User | null. Since you get compile errors without null checks, you can prevent missed checks.

Effect of These Two Options

Option Errors Prevented
noImplicitAny Crashes from operating on unknown types
strictNullChecks Crashes from null/undefined access

I delegated unused variable checking (noUnusedLocals) to Biome. TypeScript doesn't recognize _ prefixed variables, which causes issues when you only want to use part of a destructured assignment.

Division of Responsibilities: TypeScript and Biome

Biome is a tool that combines linting (code quality checking) and formatting (code styling). I chose it over ESLint because it's faster and has simpler configuration.

I divide checking responsibilities between TypeScript and Biome.

Check Item Tool Reason
Type consistency TypeScript Core strength of the type system
Null safety TypeScript Detectable at type level
Unused variables Biome Supports _ prefix convention
any type usage Biome Easier exception management with biome-ignore
Code style Biome Managed together with formatting

Here's an example Biome configuration.

{
  "linter": {
    "rules": {
      "correctness": {
        "noUnusedVariables": "warn",
        "noUnusedImports": "warn"
      },
      "suspicious": {
        "noExplicitAny": "error",
        "noDoubleEquals": "error"
      }
    }
  }
}

By setting noExplicitAny to error, I strictly limit the use of any types. When absolutely necessary, I leave a comment explaining why.

Bugs Prevented by Strict Mode

Here are typical bug patterns that strict mode can detect.

1. Missing Null Checks

The most common issue is missing null checks.

// Problematic code
function getUserName(user: User | null) {
  return user.name; // user might be null
}

With strictNullChecks enabled, this becomes a compile-time error.

// Fixed
function getUserName(user: User | null) {
  return user?.name ?? 'Anonymous';
}

This pattern is especially common with relational data. When a user is deleted, the creator field of related data becomes null. Code that doesn't account for this will crash at runtime.

2. Handling Optional Properties

Optional properties in API responses are another easy-to-miss pattern.

interface ApiResponse {
  data: {
    items: Item[];
    nextCursor?: string; // Optional
  };
}

// Problematic code
function getNextPage(response: ApiResponse) {
  return fetch(`/api?cursor=${response.data.nextCursor}`);
  // If nextCursor is undefined, this becomes "?cursor=undefined"
}
// Fixed
function getNextPage(response: ApiResponse) {
  if (!response.data.nextCursor) return null;
  return fetch(`/api?cursor=${response.data.nextCursor}`);
}

3. Type Definition and Schema Mismatch

During refactoring, it's easy to forget to update type definitions.

// Changed DB schema
// column_name → field_name

// Forgot to update type definition
interface Column {
  column_name: string; // Still using old name
}

With strict mode, everywhere using this type will show errors. You'll see red underlines in your IDE, so you won't miss any needed fixes.

IDE Benefits

When you enable strict mode, you immediately benefit in editors like VS Code.

Real-time Error Detection

When you write problematic code, red squiggly lines appear in the editor. You can catch issues before running the code, dramatically reducing debugging time.

Accurate Completions

When types are clear, property and method completion suggestions become accurate. When you type user., only properties that actually exist like name and email appear as suggestions.

Safer Refactoring

When you change a type definition, errors appear everywhere affected. You don't need to manually search for "what needs to be fixed."

// If you remove email from User type
interface User {
  id: string;
  name: string;
  // email: string;  removed
}

// Errors appear everywhere user.email is used

If there are any missed fixes, you get compile errors, so you can change code with confidence.

Preventing New Errors

Even if you fix existing errors, it's pointless if new code introduces more.

Husky is a tool for managing git hooks (scripts that run automatically on commit or push). I set up a pre-commit hook to run type checking before every commit.

#!/bin/sh
# .husky/pre-commit

echo "Running type check..."
bun run type-check

if [ $? -ne 0 ]; then
  echo "TypeScript errors found. Please fix before committing."
  exit 1
fi
{
  "scripts": {
    "type-check": "tsc --noEmit"
  }
}

Commits are blocked if there are TypeScript errors. Since "I'll fix it later" isn't allowed, errors don't accumulate.

Tips for Gradual Adoption

Here are tips for introducing strict mode to an existing project.

1. Progress Gradually

Trying to fix a large number of errors at once is discouraging. A more sustainable approach is to fix a few surrounding errors while working on features, or make only new files strict first and gradually convert the rest.

2. Document Reasons for any Types

When you absolutely need an any type, leave a comment explaining why. This allows for review when type definitions improve later.

// TODO: Type definitions will improve in library v3
// biome-ignore lint/suspicious/noExplicitAny: temporary workaround
const result = someLibrary.parse(data) as any;

3. Validate External Data with Zod

Zod is a library for runtime data validation. When you define a schema, TypeScript types are automatically generated.

For external data like API responses and form inputs, validate with Zod. This lets you manage type definitions and validation in one place.

import { z } from 'zod';

const UserSchema = z.object({
  id: z.string(),
  name: z.string(),
  email: z.string().email(),
});

type User = z.infer<typeof UserSchema>;

// Validate at runtime
const user = UserSchema.parse(apiResponse);

Summary

Here are the key points for introducing TypeScript strict mode to an existing project.

Point Details
Enable selectively Choose high-impact options rather than strict: true
Divide responsibilities Split duties between TypeScript and Biome
Fix gradually Progress bit by bit, not all at once
Prevent accumulation Make type checking mandatory with pre-commit hooks

Ideally, these settings should be enabled from the project's start. Since retrofitting them incurs fixing costs, I recommend enabling strict mode from the beginning for new projects.

Tomorrow I'll discuss "Security Measures for Solo Development."

Other Articles in This Series

  • 12/17: Implementing "Search by Meaning": Introduction to pgvector + OpenAI Embeddings
  • 12/19: Security Measures for Solo Development: The Minimum You Should Do
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten TypeScript Strict Mode in Practice: Catching Bugs with Type Safety

Thematisch verwandte Begriffe: TypeScript, Strict, Mode, Practice · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-93957 | A vulnerability has been found in olivier-ls PHP-FTS up to 1.1.3. This a…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick