3 Topics
Chapter•50 Minutes

Environment Setup and tsconfig

Install TypeScript, run the compiler, understand project configuration, and enable strict checking.

Install and Run TypeScript

For a project, install TypeScript as a development dependency so everyone and CI use the same version. npx tsc --init creates a starting tsconfig.json; npx tsc compiles the project according to that configuration. Avoid relying on an arbitrary globally installed compiler for team projects.

A minimal Node-oriented project often has src/ as input and dist/ as output. The exact module and target settings depend on whether the project uses Node ESM, CommonJS, a browser bundler, or a framework. Follow the runtime's module conventions instead of copying a configuration without understanding it.

Project setup commands
npm init -y
npm install --save-dev typescript
npx tsc --init
npx tsc --noEmit
💡 These commands create a package, install a local compiler, create a config, and type-check without emitting output. Add a build script and choose module settings that match the project's runtime.
Key Takeaways
  • Install TypeScript locally for reproducible builds.
  • tsconfig.json controls the compiler's project behavior.
  • Choose module settings to match your runtime and tooling.
Knowledge Check

Why is a local TypeScript development dependency usually preferable?

Understand tsconfig.json

tsconfig.json defines the files and compiler behavior for a TypeScript project. Important options include target (JavaScript language level), module and moduleResolution (how imports are emitted and resolved), rootDir and outDir (source/output layout), strict (strict type-checking family), and noEmit (check without output).

Do not treat compiler flags as isolated switches. For example, Node's ESM rules differ from browser bundler resolution. A project should use a configuration aligned with its deployment target and build system. Extend a framework-provided configuration when the framework expects one.

A simple Node project config
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "rootDir": "src",
    "outDir": "dist",
    "strict": true,
    "noEmitOnError": true
  },
  "include": ["src/**/*.ts"]
}
💡 This is a starting example for a modern Node ESM-oriented project, not a universal config. NodeNext behavior also depends on package metadata and file extensions. Frontend projects may use moduleResolution: "Bundler" or framework defaults.
Key Takeaways
  • target controls the JavaScript syntax level.
  • module and moduleResolution must agree with the environment.
  • strict enables a family of checks; noEmitOnError can prevent output after errors.
Knowledge Check

Which option enables the strict family of type-checking options?

Strict Mode and noImplicitAny

Strict checking is one of the highest-value choices in a new codebase. strictNullChecks makes null and undefined distinct concerns; noImplicitAny flags values whose types would otherwise silently become any; strictFunctionTypes tightens function parameter compatibility in relevant positions.

Enable strictness early, then fix errors at their source. Do not silence every error with any or as SomeType: doing so removes the evidence the compiler is providing. For legacy migrations, enable checks incrementally and track unsafe areas explicitly.

Handle an optional value
function getDisplayName(name: string | undefined): string {
  if (name === undefined) {
    return "Guest";
  }
  return name.toUpperCase();
}
💡 The guard narrows name from string | undefined to string in the remaining branch, making the call safe under strict null checking.
Key Takeaways
  • Prefer strict mode for new projects.
  • Narrow nullable values rather than hiding the error.
  • Use unknown at uncertain boundaries instead of defaulting to any.
Knowledge Check

With `strictNullChecks` enabled, what is true of `string | undefined`?