Pro programátory

TypeScript vs JavaScript - jak porovnat kód při migraci

5. února 2026
12 min čtení
typescriptjavascriptmigracerefaktoringtyped code

Migroval jsem pár JS projektů na TypeScript. Na začátku jsem se v tom ztrácel - co jsem změnil? Kde jsem přidal typy? Diff nástroje mi zachránily život.

Proč jsem to dělal

1. Statická typová kontrola

// JavaScript - chyba se projeví až za běhu
function calculateTotal(items) {
  return items.reduce((sum, item) => sum + item.price, 0);
}

// Zavoláno s nesprávným argumentem
calculateTotal("not an array"); // TypeError za běhu
// TypeScript - chyba odhalena při kompilaci
interface CartItem {
  name: string;
  price: number;
  quantity: number;
}

function calculateTotal(items: CartItem[]): number {
  return items.reduce((sum, item) => sum + item.price, 0);
}

// Kompilační chyba: Argument of type 'string' is not assignable
calculateTotal("not an array"); // Chyba už při psaní kódu

2. Lepší IntelliSense a autocomplete

S TypeScriptem získáte:

  • Automatické doplňování - IDE ví, jaké vlastnosti má objekt
  • Rychlá navigace - Ctrl+Click přejde na definici typu
  • Refaktoring - Přejmenování proměnné se propaguje správně
  • Dokumentace v kontextu - JSDoc komentáře se zobrazují inline

3. Snadnější údržba velkých projektů

U projektů nad 10 000 řádků kódu se TypeScript vyplatí:

  • Méně runtime bugů (až o 15% méně dle studií)
  • Rychlejší onboarding nových členů týmu
  • Bezpečnější refaktoring
  • Lepší spolupráce mezi frontend a backend týmy

Strategie migrace: Postupná vs. celková

Postupná migrace (doporučeno)

Většina týmů volí postupnou migraci, kdy konvertují soubor po souboru:

# Typická struktura projektu během migrace
src/
├── utils/
│   ├── helpers.ts      # Migrováno
│   ├── validators.ts   # Migrováno
│   └── formatters.js   # Čeká na migraci
├── components/
│   ├── Button.tsx      # Migrováno
│   └── Modal.js        # Čeká na migraci
└── services/
    ├── api.ts          # Migrováno
    └── auth.js         # Čeká na migraci

Výhody postupné migrace:

  • Menší riziko zanesení chyb
  • Snadnější code review
  • Možnost učit se za pochodu
  • Nezastaví vývoj nových funkcí

Celková migrace

Pro menší projekty (pod 5000 řádků) může být rychlejší konvertovat vše najednou:

# Nástroje pro hromadnou migraci
npx ts-migrate init .                    # Inicializace
npx ts-migrate rename src/               # Přejmenování .js na .ts
npx ts-migrate migrate src/              # Automatická migrace

Konfigurace TypeScript pro migraci

Základní tsconfig.json

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": false,
    "allowJs": true,
    "checkJs": false,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "outDir": "./dist"
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

Klíčové nastavení pro migraci:

  • allowJs: true - Povolí mix JS a TS souborů
  • checkJs: false - Nekontroluje JS soubory
  • strict: false - Volnější pravidla na začátku

Postupné zpřísňování

Jak migrace postupuje, zpřísňujte pravidla:

// Fáze 1: Základní
{
  "compilerOptions": {
    "strict": false,
    "noImplicitAny": false
  }
}
// Fáze 2: Středně přísné
{
  "compilerOptions": {
    "strict": false,
    "noImplicitAny": true,
    "strictNullChecks": false
  }
}
// Fáze 3: Přísné (cíl)
{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true
  }
}

Použití diff nástrojů při migraci

Porovnání před a po migraci

Při migraci jednotlivého souboru je klíčové porovnat, že se logika nezměnila:

Původní JavaScript (helpers.js):

export function formatDate(date) {
  if (!date) return '';

  const d = new Date(date);
  const day = String(d.getDate()).padStart(2, '0');
  const month = String(d.getMonth() + 1).padStart(2, '0');
  const year = d.getFullYear();

  return day + '.' + month + '.' + year;
}

export function formatCurrency(amount, currency) {
  currency = currency || 'CZK';
  return new Intl.NumberFormat('cs-CZ', {
    style: 'currency',
    currency: currency
  }).format(amount);
}

export function slugify(text) {
  return text
    .toLowerCase()
    .normalize('NFD')
    .replace(/[\u0300-\u036f]/g, '')
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/^-|-$/g, '');
}

Migrovaný TypeScript (helpers.ts):

type DateInput = Date | string | number | null | undefined;

export function formatDate(date: DateInput): string {
  if (!date) return '';

  const d = new Date(date);
  const day = String(d.getDate()).padStart(2, '0');
  const month = String(d.getMonth() + 1).padStart(2, '0');
  const year = d.getFullYear();

  return day + '.' + month + '.' + year;
}

type CurrencyCode = 'CZK' | 'EUR' | 'USD' | 'GBP';

export function formatCurrency(
  amount: number,
  currency: CurrencyCode = 'CZK'
): string {
  return new Intl.NumberFormat('cs-CZ', {
    style: 'currency',
    currency: currency
  }).format(amount);
}

export function slugify(text: string): string {
  return text
    .toLowerCase()
    .normalize('NFD')
    .replace(/[\u0300-\u036f]/g, '')
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/^-|-$/g, '');
}

Co sledovat při porovnání

Při použití diff nástroje se zaměřte na:

1. Zachování logiky - Typové anotace by neměly měnit chování

Přidání typu k parametru a návratové hodnotě je v pořádku - přidáváme pouze typy, logika zůstává stejná.

2. Změny v default hodnotách

Pozor při omezení typu na enum - ověřte, že všechna volání používají podporované hodnoty.

3. Nové typy a interface

Nově definované typy zkontrolujte, zda odpovídají reálnému použití ve zbytku kódu.

Typické vzory migrace

1. Přidání typů k parametrům funkcí

// Před (JavaScript)
function processUser(user) {
  console.log(user.name);
  user.lastLogin = new Date();
}

// Po (TypeScript)
function processUser(user: User): void {
  console.log(user.name);
  user.lastLogin = new Date();
}

2. Definice rozhraní pro objekty

// Přidejte interface pro objekty
interface User {
  id: number;
  name: string;
  email: string;
  lastLogin?: Date;
}

const users: User[] = [];

3. Ošetření null a undefined

// Před (JavaScript)
function getUsername(user) {
  return user.name;
}

// Po (TypeScript) - bezpečnější
function getUsername(user: User | null): string {
  return user?.name ?? 'Anonymous';
}

4. Převod class komponent na typed

// Přidejte typy k třídám
interface UserCache {
  [userId: string]: User;
}

class UserService {
  private apiUrl: string;
  private cache: UserCache;

  constructor(apiUrl: string) {
    this.apiUrl = apiUrl;
    this.cache = {};
  }
}

5. Migrace React komponent

import React, { FC } from 'react';

interface ButtonProps {
  onClick: () => void;
  children: React.ReactNode;
  disabled?: boolean;
}

const Button: FC<ButtonProps> = ({ onClick, children, disabled }) => {
  return (
    <button onClick={onClick} disabled={disabled}>
      {children}
    </button>
  );
};

export default Button;

Automatizace migrace pomocí nástrojů

ts-migrate od Airbnb

# Instalace
npm install -g ts-migrate

# Analýza projektu
ts-migrate check src/

# Automatická migrace s inferencí typů
ts-migrate migrate src/

# Výstup diff pro review
ts-migrate migrate src/ --dry-run > migration-diff.txt

Použití TypeScript Codemod

# Spuštění codemod pro přidání typů
npx jscodeshift -t ./codemods/add-types.js src/**/*.js

Vlastní migrační skript

// migrate-file.js
const fs = require('fs');

function migrateFile(inputPath) {
  const content = fs.readFileSync(inputPath, 'utf8');
  const outputPath = inputPath.replace('.js', '.ts');

  // Základní transformace
  let migrated = content
    // Přidání typů k běžným parametrům
    .replace(/function (\w+)\((\w+)\)/g, 'function $1($2: any)');

  fs.writeFileSync(outputPath, migrated);
  console.log('Migrated: ' + inputPath + ' -> ' + outputPath);
}

Code review při migraci

Checklist pro review migrovaného souboru

Při code review migrovaného kódu kontrolujte:

Typová bezpečnost:

  • Jsou všechny any typy oprávněné?
  • Jsou interface kompletní?
  • Jsou ošetřeny null a undefined?
  • Odpovídají typy reálnému použití?

Zachování funkcionality:

  • Nezměnila se business logika?
  • Jsou výchozí hodnoty stejné?
  • Fungují edge cases jako předtím?

Kvalita kódu:

  • Jsou typy dostatečně specifické (ne jen any nebo object)?
  • Jsou složené typy pojmenované (interface/type alias)?
  • Je kód čitelnější než před migrací?

Git workflow pro migraci

# Vytvoření feature branch
git checkout -b feature/typescript-migration-utils

# Migrace jednoho modulu
mv src/utils/helpers.js src/utils/helpers.ts
# ... úpravy ...

# Commit s popisným názvem
git commit -m "refactor(utils): migrate helpers.js to TypeScript"

# Pull request s jasným diff
gh pr create --title "TypeScript migration: utils module"

Řešení běžných problémů

1. "Cannot find module" po přejmenování

# Problém: Import stále hledá .js soubor
import { helper } from './helpers.js'; // Nefunguje

# Řešení: Odstraňte příponu
import { helper } from './helpers'; // Funguje

2. Conflict typů z node_modules

// Problém: Nekompatibilní typy
import { Request } from 'express';

// Řešení: Vlastní rozšíření typů
// types/express.d.ts
declare namespace Express {
  interface Request {
    user?: {
      id: string;
      role: string;
    };
  }
}

3. Cirkulární závislosti typů

// Problém: User potřebuje Order, Order potřebuje User

// Řešení: Společný types soubor
// types/index.ts
export interface User {
  id: string;
  orders: Order[];
}

export interface Order {
  id: string;
  userId: string;
  user?: User; // Lazy reference
}

4. Third-party knihovny bez typů

# Zkusit nainstalovat @types balíček
npm install --save-dev @types/lodash

# Pokud neexistuje, vytvořit vlastní deklaraci
# types/legacy-lib.d.ts
declare module 'legacy-lib' {
  export function doSomething(input: string): void;
  export const VERSION: string;
}

Měření postupu migrace

Sledování progress pomocí skriptu

#!/bin/bash
# migration-progress.sh

echo "=== TypeScript Migration Progress ==="
echo ""

total_js=$(find src -name "*.js" -o -name "*.jsx" | wc -l)
total_ts=$(find src -name "*.ts" -o -name "*.tsx" | wc -l)
total=$((total_js + total_ts))

if [ $total -gt 0 ]; then
  percent=$((total_ts * 100 / total))
  echo "JavaScript files: $total_js"
  echo "TypeScript files: $total_ts"
  echo "Progress: $percent%"
fi

Shrnutí

Migrace z JavaScriptu na TypeScript je investice, která se vyplatí. S pomocí diff nástrojů můžete:

  1. Bezpečně sledovat změny - Porovnáním před/po zajistíte, že se nezměnila logika
  2. Efektivně reviewovat - Diff jasně ukazuje, co se přidalo (typy) vs. co se změnilo (logika)
  3. Postupně migrovat - Soubor po souboru s plnou kontrolou
  4. Dokumentovat progress - Git historie ukazuje postup migrace

Klíčové tipy pro úspěšnou migraci:

  • Začněte s strict: false a postupně zpřísňujte
  • Migrujte utility a sdílený kód jako první
  • Používejte automatizační nástroje (ts-migrate)
  • Code review každý migrovaný soubor
  • Testujte průběžně

Potřebujete porovnat JavaScript a TypeScript verzi vašeho kódu? Vyzkoušejte náš Code Diff nástroj – podporuje oba jazyky a zvýrazní přesně, které řádky se změnily.

Vyzkoušejte PorovnejText.cz zdarma

Nejrychlejší český nástroj pro porovnání textů. Vše probíhá ve vašem prohlížeči, žádná registrace není potřeba.

Porovnat texty nyní →