Vývoj v TypeScriptu
TypeScript Development Guide
This comprehensive guide covers TypeScript programming, including core concepts, advanced features, tooling, and best practices for modern web development.
Getting Started with TypeScript
Installation and Setup
Global Installation:
npm install -g typescript
Project Setup:
# Initialize npm project
npm init -y
# Install TypeScript locally
npm install --save-dev typescript
# Initialize TypeScript configuration
npx tsc --init
Basic tsconfig.json:
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
TypeScript Fundamentals
Basic Types
Primitive Types:
// String, number, boolean
let name: string = "John";
let age: number = 30;
let isStudent: boolean = false;
// Array types
let numbers: number[] = [1, 2, 3, 4];
let names: Array<string> = ["Alice", "Bob"];
// Tuple (fixed-length array)
let person: [string, number] = ["John", 30];
// Enum
enum Color {
Red,
Green,
Blue
}
let color: Color = Color.Red;
// Any (avoid when possible)
let anything: any = "could be anything";
// Void (for functions that don't return)
function logMessage(): void {
console.log("Hello!");
}
// Never (for functions that never return)
function throwError(message: string): never {
throw new Error(message);
}
Interfaces and Type Aliases
Interfaces:
interface User {
id: number;
name: string;
email: string;
isActive?: boolean; // Optional property
readonly createdAt: Date; // Read-only property
}
// Extending interfaces
interface Admin extends User {
role: string;
permissions: string[];
}
// Interface for functions
interface Comparator<T> {
(a: T, b: T): number;
}
// Interface for indexable types
interface Dictionary<T> {
[key: string]: T;
}
Type Aliases:
// Simple type alias
type UserId = number;
// Union types
type Status = "active" | "inactive" | "pending";
// Intersection types
type AdminUser = User & { role: string };
// Generic type alias
type ApiResponse<T> = {
data: T;
status: number;
message: string;
};
Classes
Basic Class:
class Person {
// Properties
public name: string;
private age: number;
protected email: string;
// Constructor
constructor(name: string, age: number, email: string) {
this.name = name;
this.age = age;
this.email = email;
}
// Methods
public greet(): string {
return `Hello, my name is ${this.name}`;
}
// Getter
get fullInfo(): string {
return `${this.name} (${this.age} years old)`;
}
// Setter
set updateEmail(newEmail: string) {
this.email = newEmail;
}
}
// Usage
const person = new Person("John", 30, "john@example.com");
console.log(person.greet());
Inheritance:
class Employee extends Person {
private salary: number;
constructor(name: string, age: number, email: string, salary: number) {
super(name, age, email);
this.salary = salary;
}
// Override method
greet(): string {
return `Hello, I'm ${this.name} and I work here.`;
}
// New method
getSalary(): number {
return this.salary;
}
}
Abstract Classes:
abstract class Shape {
abstract getArea(): number;
abstract getPerimeter(): number;
// Concrete method
describe(): string {
return `Area: ${this.getArea()}, Perimeter: ${this.getPerimeter()}`;
}
}
class Rectangle extends Shape {
constructor(private width: number, private height: number) {
super();
}
getArea(): number {
return this.width * this.height;
}
getPerimeter(): number {
return 2 * (this.width + this.height);
}
}
Generics
Generic Functions:
function identity<T>(arg: T): T {
return arg;
}
// Usage
let output1 = identity<string>("Hello");
let output2 = identity<number>(42);
// Multiple type parameters
function combine<T, U>(first: T, second: U): [T, U] {
return [first, second];
}
Generic Classes:
class Stack<T> {
private items: T[] = [];
push(item: T): void {
this.items.push(item);
}
pop(): T | undefined {
return this.items.pop();
}
peek(): T | undefined {
return this.items[this.items.length - 1];
}
isEmpty(): boolean {
return this.items.length === 0;
}
}
// Usage
const numberStack = new Stack<number>();
numberStack.push(1);
numberStack.push(2);
console.log(numberStack.pop()); // 2
Generic Constraints:
interface Lengthwise {
length: number;
}
function logLength<T extends Lengthwise>(arg: T): T {
console.log(arg.length);
return arg;
}
// Usage
logLength("Hello"); // OK
logLength([1, 2, 3]); // OK
logLength(42); // Error: number has no length property
Advanced TypeScript Features
Union and Intersection Types
Union Types:
type StringOrNumber = string | number;
function formatValue(value: StringOrNumber): string {
if (typeof value === "string") {
return value.toUpperCase();
} else {
return value.toFixed(2);
}
}
// Discriminated unions
type SuccessResponse = { success: true; data: any };
type ErrorResponse = { success: false; error: string };
type ApiResponse = SuccessResponse | ErrorResponse;
function handleResponse(response: ApiResponse) {
if (response.success) {
console.log("Data:", response.data);
} else {
console.error("Error:", response.error);
}
}
Intersection Types:
type Timestamped = { timestamp: Date };
type Named = { name: string };
type TimestampedNamed = Timestamped & Named;
// Equivalent to:
// type TimestampedNamed = {
// timestamp: Date;
// name: string;
// }
Type Guards and Assertions
Type Guards:
function isString(value: unknown): value is string {
return typeof value === "string";
}
function isNumber(value: unknown): value is number {
return typeof value === "number";
}
function processValue(value: unknown) {
if (isString(value)) {
console.log("String length:", value.length);
} else if (isNumber(value)) {
console.log("Number squared:", value * value);
}
}
Type Assertions:
// Angle-bracket syntax
let someValue: unknown = "hello world";
let strLength: number = (<string>someValue).length;
// as syntax (recommended)
let strLength2: number = (someValue as string).length;
// Non-null assertion
function process(user: User | null) {
console.log(user!.name); // Asserts user is not null
}
Utility Types
Built-in Utility Types:
interface Todo {
id: number;
title: string;
completed: boolean;
createdAt: Date;
}
// Partial - makes all properties optional
type PartialTodo = Partial<Todo>;
// Required - makes all properties required
type RequiredTodo = Required<Todo>;
// Pick - selects specific properties
type TodoPreview = Pick<Todo, "id" | "title">;
// Omit - removes specific properties
type TodoWithoutId = Omit<Todo, "id">;
// Readonly - makes all properties readonly
type ReadonlyTodo = Readonly<Todo>;
Custom Utility Types:
// Extract function return type
type ReturnTypeOf<T> = T extends (...args: any[]) => infer R ? R : never;
// Extract promise resolved type
type Awaited<T> = T extends PromiseLike<infer U> ? U : T;
// Make specific properties optional
type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
TypeScript Compiler (tsc) Commands
Basic Compilation
Compile all files:
npx tsc
Compile specific file:
npx tsc file.ts
Initialize TypeScript project:
npx tsc --init
Watch Mode and Output
Watch mode (continuous compilation):
npx tsc --watch
npx tsc -w
Specify output directory:
npx tsc --outDir ./dist
Specify root directory:
npx tsc --rootDir ./src
Compilation Options
Target ECMAScript version:
npx tsc --target ES2020
npx tsc --target ES5
Module system:
npx tsc --module commonjs
npx tsc --module es2020
Include/exclude files:
npx tsc --include src/**/*.ts
npx tsc --exclude node_modules
Type Checking and Diagnostics
Strict type checking:
npx tsc --strict
Type check without emitting files:
npx tsc --noEmit
Generate declaration files:
npx tsc --declaration
Generate source maps:
npx tsc --sourceMap
Project Configuration
Use specific tsconfig.json:
npx tsc --project ./path/to/tsconfig.json
npx tsc -p ./path/to/tsconfig.json
Incremental compilation:
npx tsc --incremental
Remove comments from output:
npx tsc --removeComments
Module Systems
ES6 Modules
Export:
// Named exports
export const PI = 3.14159;
export function calculateArea(radius: number): number {
return PI * radius * radius;
}
// Default export
export default class Calculator {
add(a: number, b: number): number {
return a + b;
}
}
Import:
// Named imports
import { PI, calculateArea } from './math';
// Default import
import Calculator from './calculator';
// Rename imports
import { calculateArea as area } from './math';
// Import all
import * as MathUtils from './math';
CommonJS (Node.js)
Export:
// Single export
export = function() {
return "Hello";
};
// Or using module.exports
const utils = {
add: (a: number, b: number) => a + b,
multiply: (a: number, b: number) => a * b
};
export = utils;
Import:
// Import CommonJS module
import utils = require('./utils');
Decorators
Class Decorators:
function sealed(constructor: Function) {
Object.seal(constructor);
Object.seal(constructor.prototype);
}
@sealed
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
Method Decorators:
function enumerable(value: boolean) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.enumerable = value;
};
}
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
@enumerable(false)
greet() {
return "Hello, " + this.greeting;
}
}
Error Handling and Debugging
Error Types
Custom Error Classes:
class ValidationError extends Error {
constructor(message: string, public field: string) {
super(message);
this.name = 'ValidationError';
}
}
class NetworkError extends Error {
constructor(message: string, public statusCode: number) {
super(message);
this.name = 'NetworkError';
}
}
Error Handling Patterns:
async function fetchData(url: string): Promise<any> {
try {
const response = await fetch(url);
if (!response.ok) {
throw new NetworkError('Network request failed', response.status);
}
return await response.json();
} catch (error) {
if (error instanceof NetworkError) {
console.error(`Network error ${error.statusCode}: ${error.message}`);
} else if (error instanceof ValidationError) {
console.error(`Validation error for ${error.field}: ${error.message}`);
} else {
console.error('Unknown error:', error);
}
throw error;
}
}
Testing with TypeScript
Using Jest
Setup:
npm install --save-dev jest @types/jest ts-jest
npx ts-jest config:init
Basic Test:
// sum.ts
export function sum(a: number, b: number): number {
return a + b;
}
// sum.test.ts
import { sum } from './sum';
describe('sum', () => {
it('should add two numbers', () => {
expect(sum(1, 2)).toBe(3);
});
it('should handle negative numbers', () => {
expect(sum(-1, 1)).toBe(0);
});
});
Test Configuration (jest.config.js)
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
roots: ['<rootDir>/src', '<rootDir>/tests'],
testMatch: ['**/__tests__/**/*.ts', '**/?(*.)+(spec|test).ts'],
collectCoverageFrom: [
'src/**/*.ts',
'!src/**/*.d.ts',
],
};
Best Practices
Code Organization
File Structure:
src/ ├── types/ ├── interfaces/ ├── utils/ ├── services/ ├── components/ └── index.tsNaming Conventions:
- Use PascalCase for classes, interfaces, and type aliases
- Use camelCase for variables, functions, and properties
- Use UPPER_CASE for constants
Type Safety:
- Avoid
anytype when possible - Use strict mode in tsconfig.json
- Leverage union types for better type safety
- Avoid
Performance Considerations
Tree Shaking: Use ES6 modules for better bundling
Type-Only Imports: Import types without runtime overhead
import type { User } from './types';Declaration Files: Generate .d.ts files for libraries
Tooling and Development
ESLint Configuration:
{
"extends": [
"eslint:recommended",
"@typescript-eslint/recommended"
],
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint"],
"rules": {
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/explicit-function-return-type": "warn"
}
}
Prettier Configuration:
{
"semi": true,
"trailingComma": "es5",
"singleQuote": true,
"printWidth": 80,
"tabWidth": 2
}
Learning Resources
- Official Documentation: https://www.typescriptlang.org/docs/
- TypeScript Handbook: https://www.typescriptlang.org/docs/handbook/intro.html
- Microsoft Learn: https://learn.microsoft.com/en-us/training/browse/?terms=typescript
- TypeScript Deep Dive: https://basarat.gitbook.io/typescript/
This guide provides a comprehensive foundation for TypeScript development, covering core concepts, advanced features, tooling, and best practices for building robust applications.