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 |
|---|---|
noImplicitAny | A value that quietly became any because you forgot a type |
strictNullChecks | Using a value that might be null or undefined |
strictFunctionTypes | Passing 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.
// 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.
// 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:
- The library is written in TypeScript (or ships its own types) — types just work, nothing to do.
- The library is plain JavaScript but the community publishes types separately — you install a matching
@typespackage. - 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:
# install the library, then its community types
npm install lodash
npm install --save-dev @types/lodashNote: 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".
// 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?
✍️ Practice
- In a tsconfig.json, confirm
"strict": trueis set, then write a function that uses astring | undefinedvalue and fix the error strictNullChecks reports. - Install any small JS library plus its
@typespackage and import it to confirm autocomplete now works.
🏠 Homework
- Write a short
globals.d.tsthat declares two things you might add towindow(e.g. aanalyticsId: stringand atrack(name: string): voidfunction). Explain in one sentence why a .d.ts produces no JavaScript.