Skip to main content
This lesson summarizes practical, project-level best practices for organizing and maintaining TypeScript codebases. These are pragmatic recommendations — not hard rules — because TypeScript is used for many contexts (backend APIs, front-end apps, infrastructure-as-code, libraries, etc.). Apply the guidance that fits your project and team.
Best practices depend on your use case. What’s ideal for a NestJS backend may not fit a React SPA or an IaC project. Treat these recommendations as adaptable guidance rather than dogma.

Organize code across multiple files

Prefer small files with a single responsibility. Clear separation of concerns improves readability, testability, and parallel collaboration.
  • Group related types, functions, and classes, but keep files focused (e.g., one service, one module, one logical unit).
  • Avoid very large files that mix responsibilities; split them into smaller units.
  • Use index (barrel) files sparingly: they can simplify imports but may also hide large dependency graphs and create circular-dependency risks.
A slide titled "TypeScript Project – Best Practices" listing recommendations like organizing code across multiple files, encapsulating related logic with classes/interfaces and pure functions, and using linting/formatting tools. It also includes brief bullets explaining separation of concerns, improved collaboration, and tools like ESLint and Prettier.
Some ecosystems favor classes and dependency injection (e.g., NestJS), while others favor functional composition. Either is fine — consistency and clear conventions matter most. Group behavior and data where it belongs so each unit has a clear contract and responsibilities.
  • Classes & interfaces: good for explicit contracts and shared behavior across implementations.
  • Pure functions: prefer small, deterministic functions with no side effects where possible — easier to test and reason about.
  • Modules: expose a minimal public surface, keep implementation details private to the module.
Example — pure function vs. impure:

Linting and formatting

Run automated linting and formatting to maintain code quality and consistent style across the team.
  • ESLint: catch likely bugs and enforce code-quality rules (unused vars, unreachable code, consistent use of const, etc.).
  • Prettier: enforce formatting (line breaks, quotes, spacing). Prefer letting Prettier handle formatting and ESLint handle semantics.
  • Integrate @typescript-eslint/parser and @typescript-eslint/eslint-plugin for TypeScript support.
  • Use eslint-config-prettier to avoid rule conflicts between ESLint and Prettier.
  • Add checks to pre-commit hooks (husky + lint-staged) and to CI pipelines.
Typical tooling setup: Integrate linting and formatting into CI to ensure consistent quality across pull requests.

File and identifier naming

Pick a convention early and stick to it. Document it in your repository’s style guide and enforce via linters. Examples in code:

Additional practical items

  • tsconfig: enable strict early and consider noImplicitAny, strictNullChecks, and noUncheckedIndexedAccess to catch issues early.
  • Types: prefer explicit types on public APIs; rely on inference for local variables when it improves readability.
  • Tests: unit tests for pure logic; integration tests for external interactions (databases, network, etc.).
  • Scripts: include helpful npm scripts: npm run build, npm run lint, npm test, npm run typecheck.
  • CI: run lint, typecheck, and tests in CI for every PR to avoid regressions.
  • Dependencies: keep devDependencies separate from runtime dependencies; rely on lockfiles and update dependencies deliberately.
Enable TypeScript strict mode early in a project to catch subtle bugs. Migrating a large codebase to strict later can be time-consuming.

Example naming summary

Conclusion

These guidelines provide a practical starting point for structuring TypeScript projects. Focus on clarity, consistency, and automation (linting, formatting, CI). Decide conventions early, document them in a style guide, and enforce them with tools so your team can move fast without sacrificing maintainability. This lesson covered project-level best practices. Subsequent lessons will show how to apply these patterns in real applications and concrete examples.

Watch Video