Expert · TypeScript basics · topic 55 of 64 · 40 min
TypeScript in real projects
Explanation
tsconfig.json: the project settings
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"strict": true,
"noEmit": true,
"skipLibCheck": true
},
"include": ["src"]
}| Option | What it does |
|---|---|
| strict | Turns on the strong checks, including strictNullChecks and noImplicitAny. Keep it on. |
| target | Which JavaScript version the output uses; ES2022 keeps modern syntax |
| module, moduleResolution | How import and export work; "bundler" fits Vite and similar tools |
| lib | Which built-in APIs exist; "DOM" adds document, window and fetch |
| noEmit | Only check, write no .js files, because the bundler builds the code |
| allowJs, checkJs | Let .js files join the project, and check them too |
Typing DOM code
const input = document.querySelector<HTMLInputElement>("#pin");
if (!input) throw new Error("PIN input is missing");
input.value = "560001"; // OK: input is HTMLInputElement here
const form = document.querySelector("form"); // HTMLFormElement | null
form?.addEventListener("submit", (event) => {
event.preventDefault(); // event is inferred as SubmitEvent
});
document.addEventListener("keydown", (e) => {
console.log(e.key); // e is KeyboardEvent
});Do not trust API JSON
response.json() gives back any. Writing as Product[] just believes the server. If the server sends price as "120" (text) or forgets a field, the bug reaches your users. Treat the reply as unknown and check it.
async function loadProducts(): Promise<Product[]> {
const res = await fetch("/api/products");
if (!res.ok) throw new Error("HTTP " + res.status);
const data: unknown = await res.json();
if (!Array.isArray(data)) throw new Error("Expected a list");
return data.filter(isProduct); // isProduct is a type guard
}
// With a schema library such as Zod, one description gives the check AND the type:
// const ProductSchema = z.object({ id: z.string(), name: z.string(), price: z.number() });
// type Product = z.infer<typeof ProductSchema>;
// const product = ProductSchema.parse(data); // throws if the shape is wrongType assertions (as) and the non-null !
const total = document.getElementById("total") as HTMLSpanElement; // "trust me, it is a span"
const button = document.querySelector("button")!; // "trust me, it is not null"
// If you are wrong, the app crashes at runtime: TypeScript believed you.Prefer a real check (if, a type guard) over as and !. Use as only when you truly know more than the compiler, for example just after you created the element yourself.
Types for libraries: .d.ts files and @types
A .d.ts file (a declaration file) contains only types, no code. Most modern npm packages ship their own. For older JavaScript libraries, the community DefinitelyTyped project publishes types as separate @types packages, installed with npm install -D @types/<name>. If VS Code says it could not find a declaration file for a module, look for an @types package first.
Moving a JavaScript project to TypeScript
- Add // @ts-check as the first line of a .js file: VS Code starts checking it, with no build change.
- Add a tsconfig.json with "allowJs": true, so .js and .ts files can live together.
- Rename one file at a time from .js to .ts (or .jsx to .tsx) and fix its errors.
- Turn strict on for new code; in a large old project, turn options on step by step.
- Replace any with real types as you go.
Reading common compiler errors
| Error (short) | What it means | Usual fix |
|---|---|---|
| TS2322: Type 'X' is not assignable to type 'Y' | A value of the wrong type is stored | Fix the value, or the type if the type is wrong |
| TS2345: Argument of type 'X' is not assignable to parameter of type 'Y' | A function got the wrong kind of argument | Convert first, e.g. Number(text) |
| TS2339: Property 'x' does not exist on type 'Y' | A typo, or the type does not have that field | Fix the spelling, add the field, or narrow first |
| TS18047: 'x' is possibly 'null' | The value might be null | Check with if, or use ?. and ?? |
| TS7006: Parameter 'x' implicitly has an 'any' type | A parameter has no type under strict | Add a type to the parameter |
Watch the lesson
TypeScript in real projects · 1/8
tsconfig dot json holds the project settings. Always turn strict on.
Prefer a video by a teacher? Find free videos on “typescript tsconfig strict mode migrate javascript to typescript” on YouTube ↗
In real life: A PIN code lookup form
A delivery app has a PIN code box. The TypeScript code gets the input with querySelector<HTMLInputElement>, checks it is not null, and reads the value on submit. It calls an API for the area name, takes the reply as unknown, and uses a type guard to check it has a string area and a boolean deliverable before showing "Delivery available in Koramangala". When the API team renamed area to areaName, the check caught it on the first test run instead of showing "undefined" to customers.
Practice (0/3 done)
Convert a small JavaScript file to TypeScript. Take a file from one of your earlier projects (for example the shopping cart or the form code from the DOM module). First add // @ts-check at the top and fix what VS Code reports. Then add a tsconfig.json with "strict": true and "allowJs": true, rename the file to .ts, add types for the parameters and the main objects, and run npx tsc --noEmit until it prints no errors.
type Product = { id: string; name: string; price: number }. Write a type guard isProduct(value: unknown): value is Product that returns true only when value is an object (not null) whose id and name are strings and whose price is a number. isProduct({ id: "p1", name: "Tea", price: 40 }) is true; isProduct({ id: "p1", name: "Tea", price: "40" }) is false; isProduct(null) is false.
Write parseProducts(json: string): Product[]. It parses the JSON text. If the text is not valid JSON, or the result is not an array, return []. Otherwise return only the items that pass isProduct (already written for you in the starter). For the text of [{ "id": "p1", "name": "Tea", "price": 40 }, { "id": "p2", "name": "Milk" }] it returns only the tea product.
Quick quiz
Read more (free)
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.