TypeScript Fundamentals: Types, Generics and Real-World Patterns · TypeScript Basics: Types, Narrowing and Functions
Hello, TypeScript: Types, Inference and Strict Mode
Write your first typed program, see how inference removes most annotations, use unknown instead of any, and learn how the compiler reports mistakes before the code runs.
What you'll build
A small distance converter. Along the way you'll annotate a function, rely on type inference, handle an unknown value safely and see the compiler reject a wrong call.
The idea
TypeScript is JavaScript with a type system. You describe what values are allowed, and the compiler checks your code before it runs. The types are erased when the code is compiled, so the output is plain JavaScript that runs in browsers, Node.js, Deno and Bun.
Set up a project and compile:
npm install --save-dev typescript
npx tsc --init # creates tsconfig.json
npx tsc # type-checks and compiles to JavaScript
npx tsc --noEmit # type-check only (a common CI step)
Turn on "strict": true in tsconfig.json. It enables the checks that catch the most bugs, including null and undefined safety, and every example in this course uses it.
Three ideas to learn first:
- Annotations state a type:
const label: string = "Marathon";,function convert(distance: number): number. - Inference works the type out for you:
const trip = 42.195;is already anumber. Annotate function parameters and return values; let inference handle most variables. unknownvsany.anyswitches the checker off for a value.unknownmeans "could be anything", and you must check it before use. Preferunknown.
The code
type Unit = "km" | "mi";
function convert(distance: number, from: Unit): number {
return from === "km" ? distance * 0.621371 : distance / 0.621371;
}
const trip = 42.195; // inferred: number
const label: string = "Marathon";
console.log(`${label}: ${trip} km = ${convert(trip, "km").toFixed(2)} mi`);
// The compiler rejects wrong calls. @ts-expect-error documents an error we expect here.
// @ts-expect-error: a string is not a number
convert("42", "km");
// unknown must be checked before use
function describe(value: unknown): string {
if (typeof value === "number") return `a number: ${value.toFixed(1)}`;
if (typeof value === "string") return `a string: ${value.toUpperCase()}`;
return "something else";
}
console.log(describe(3.14159));
console.log(describe("hello"));
console.log(describe([1, 2]));
Output
Marathon: 42.195 km = 26.22 mi a number: 3.1 a string: HELLO something else
Remove the @ts-expect-error line in your own editor and the call convert("42", "km") gets a red underline: Argument of type 'string' is not assignable to parameter of type 'number'. That message is the whole point of TypeScript.
Common mistakes
- Turning strict mode off to silence errors. Fix the code instead; the errors are real bugs waiting to happen.
- Annotating everything.
const count: number = 0;adds noise. Annotate function signatures and exported values; let the compiler infer locals. - Using
anyas an escape hatch. It spreads: oneanymakes everything derived from it unchecked. Useunknownand narrow. - Assuming types exist at runtime. They are erased, so you cannot test
typeof x === "Unit". Runtime checks use JavaScript values (typeof,in,instanceof). - Forgetting to compile. Browsers and Node.js run JavaScript. Use
tsc, a bundler, or a runner such astsx; recent Node.js versions can also run.tsfiles that use only erasable syntax.
Key points
- TypeScript checks types at compile time and erases them, producing plain JavaScript.
- Enable
"strict": true. Annotate function parameters and returns, and let inference do the rest. - Use
unknownfor values of uncertain type and narrow them withtypeofbefore use; avoidany. - A string-literal union such as
"km" | "mi"restricts a value to specific strings.
Further reading: The TypeScript Handbook: The Basics.
Practice questions
What is the difference between `any` and `unknown`?
Answer
any turns type checking off for that value, so anything is allowed and the unsafety spreads. unknown also accepts any value but forces you to narrow it (for example with typeof) before you can use it.
Why can't you write `if (x instanceof Unit)` when `Unit` is a type alias?
Answer
Types are erased at compile time, so they do not exist when the program runs. Runtime checks must use JavaScript values such as typeof, in, instanceof with a class, or comparisons.
Open in the app to mark lessons complete, take notes and track your progress.