Going DeeperPro· 40 min read

Strict Mode, @types & Declaration Files

Turn on the safety flags that make TypeScript worth using, and learn how types arrive for third-party JavaScript libraries.

What you will learn

  • Understand strict, strictNullChecks and noImplicitAny
  • Install types for a library with @types
  • Write a tiny declaration file (.d.ts) for untyped JS

Strict mode: where TypeScript’s real safety lives

You met tsconfig.json earlier and the "strict": true flag. That one switch turns on a family of stricter checks. They are what separate "TypeScript that catches real bugs" from "TypeScript that barely helps". The three you must know:

Flag (inside strict)What it catches
noImplicitAnyA value that quietly became any because you forgot a type
strictNullChecksUsing a value that might be null or undefined
strictFunctionTypesPassing a function with incompatible parameter types

noImplicitAny — no silent any

Without it, a parameter with no type silently becomes any and loses all checking. With it on, TypeScript makes you say what the type is.

A parameter with no type, under noImplicitAny
// With "noImplicitAny": true
function greet(name) {        // no type on name
  return 'Hi ' + name;
}

Note: Output: Error: Parameter 'name' implicitly has an 'any' type. The flag refuses to let name default to any. You fix it by writing name: string — closing a hole where untyped, unchecked values would otherwise flow through your code.

strictNullChecks — the billion-dollar bug catcher

This is the most valuable flag. With it on, null and undefined are not allowed everywhere — you must handle the "missing" case before using a value. It catches the single most common crash in real apps: reading a property of something that is not there.

Using a possibly-undefined value, under strictNullChecks
// With "strictNullChecks": true
function firstLetter(text: string | undefined): string {
  return text[0];     // error — text might be undefined
}

Note: Output: Error: 'text' is possibly 'undefined'. TypeScript forces you to check first, e.g. if (text) return text[0];. Without this flag, the code would compile and then crash at runtime with "Cannot read properties of undefined" — the classic bug strictNullChecks exists to stop.

Tip: Always keep "strict": true on in tsconfig.json. New projects from tsc --init enable it by default. Turning it off to silence errors throws away most of the value TypeScript gives you.

Third-party libraries: where do their types come from?

When you import a library from npm, TypeScript needs to know its types. There are three situations:

  1. The library is written in TypeScript (or ships its own types) — types just work, nothing to do.
  2. The library is plain JavaScript but the community publishes types separately — you install a matching @types package.
  3. No types exist anywhere — you write a small declaration file yourself.

@types and DefinitelyTyped

DefinitelyTyped is a huge community repository of type definitions for popular JavaScript libraries. Its packages are published under the @types scope. If you install a JS-only library and the editor complains it has no types, install its @types partner:

Terminal: add types for a JavaScript library
# install the library, then its community types
npm install lodash
npm install --save-dev @types/lodash

Note: Output: added 1 package added 1 package Now import _ from 'lodash' is fully typed: autocomplete and checking work, even though lodash itself is plain JavaScript. The @types/lodash package supplied the type information separately.

Declaration files (.d.ts): types with no code

A declaration file ends in .d.ts and contains *only* type information — no runnable code. It is how you describe the shape of JavaScript that has no types. The declare keyword says "this thing exists elsewhere; here is its type".

A tiny .d.ts describing an untyped global function and constant
// legacy.d.ts — describing an untyped global from a JS script
declare function trackEvent(name: string, value: number): void;

declare const APP_VERSION: string;

Note: Output: (No output — a .d.ts produces no JavaScript at all.) After this file exists, calling trackEvent('click', 1) elsewhere is fully type-checked, and APP_VERSION is known to be a string — even though the real code lives in a plain JS file TypeScript never sees.

Watch out: A .d.ts only *describes* types; it never creates the actual function or value. If you declare something that does not really exist at runtime, your code will compile but crash. Declaration files are a promise about JavaScript that must already be there.

Q. You install a plain-JavaScript npm library and your editor says it has no type definitions. What is the usual fix?

Answer: Most popular JS libraries have community-maintained types on DefinitelyTyped, published as @types/<name>. Installing that package gives the library full type support.

✍️ Practice

  1. In a tsconfig.json, confirm "strict": true is set, then write a function that uses a string | undefined value and fix the error strictNullChecks reports.
  2. Install any small JS library plus its @types package and import it to confirm autocomplete now works.

🏠 Homework

  1. Write a short globals.d.ts that declares two things you might add to window (e.g. a analyticsId: string and a track(name: string): void function). Explain in one sentence why a .d.ts produces no JavaScript.
Want to learn this with a mentor?

CodingClave runs guided, project-based training (28-day, 45-day & 6-month batches).

Explore Training →