What Is TypeScript and How Do You Use It?
TypeScript is a typed superset of JavaScript: every valid JavaScript program is also valid TypeScript, but TypeScript adds optional static types that a compiler checks before your code ever runs. You use it by installing the typescript package, writing .ts files, and compiling them to plain .js with the tsc command. It fits best when a codebase grows past a few files or several people, where catching type errors at build time is cheaper than debugging them at runtime. For a throwaway script, plain JavaScript is usually faster to write.
What TypeScript actually adds
TypeScript does not change how JavaScript runs. Browsers and Node.js still execute JavaScript, so the types are erased during compilation. What you gain is a checking pass:
- Static type checking — the compiler reads your annotations and flags mismatches before execution.
- Earlier error detection — mistakes like calling a method that does not exist surface in your editor or in
tsc, not in production. - Better tooling — editors use the type information for autocomplete, inline documentation, and safe rename/refactor operations.
- Self-documenting interfaces — function signatures and object shapes describe intent without extra comments.
The trade-off is a build step and some annotation overhead. Types are optional, so you can adopt them gradually.
The basic workflow
1. Install the compiler
npm install --save-dev typescript
This adds tsc to your project. You can also install it globally, but a local dev dependency keeps the version consistent across machines and CI.
2. Write a .ts file
function greet(name: string): string {
return `Hello, ${name}`;
}
console.log(greet("Ada"));
The : string annotations tell the compiler what name and the return value must be. If you call greet(42), tsc reports an error instead of letting it fail silently at runtime.
3. Compile
npx tsc greet.ts
Expected result: a greet.js file next to the source, containing the same logic with the type annotations removed. That .js file is what Node.js or the browser runs.
4. Add a config file
For anything beyond one file, create a tsconfig.json so you do not repeat flags:
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"strict": true,
"outDir": "dist"
},
"include": ["src"]
}
Then just run npx tsc. strict: true turns on the stricter checks, including strictNullChecks, which is where most real-world type safety comes from. Turning it on later in a large project is painful, so enable it early.
Key features with examples
Type annotations
let count: number = 0;
let names: string[] = ["Ada", "Grace"];
Annotations can be omitted when TypeScript can infer the type, which it does for most assignments.
Interfaces
interface User {
id: number;
email: string;
nickname?: string; // optional
}
function sendWelcome(user: User) {
console.log(`Welcome, ${user.nickname ?? user.email}`);
}
An interface describes the shape an object must have. Passing an object missing id or email is a compile error.
Generics
function first<T>(items: T[]): T | undefined {
return items[0];
}
const n = first([1, 2, 3]); // n: number | undefined
const s = first(["a", "b"]); // s: string | undefined
Generics let one function work across types while keeping the relationship between input and output. T is a placeholder filled in at the call site.
Using TypeScript in an existing JavaScript project
You do not have to convert everything at once:
- Add
typescriptand atsconfig.jsonwith"allowJs": trueso.jsfiles are included. - Rename files to
.tsone at a time, starting with the most central modules. - Add types to function boundaries first — parameters and return values — and let inference handle the internals.
- Turn on
strictonce the obvious errors are cleared.
Most build tools and bundlers accept TypeScript through a loader or plugin, so you rarely need to run tsc by hand in a modern setup. In monorepos, tools like Lerna manage multiple JavaScript/TypeScript packages from one repository, and each package can carry its own tsconfig.json while sharing a base config. That is a common reason teams introduce TypeScript: a shared type contract between packages catches breaking changes at build time rather than at integration.
Common sticking points
anyeverywhere — annotating everything asanydisables the checks you installed TypeScript for. Preferunknownand narrow it.- Ignoring
strictNullChecks— most runtime crashes come fromnull/undefined, which this flag catches. - Types at runtime — TypeScript types do not exist after compilation, so you still need runtime validation for data from APIs, files, or user input.
- Build configuration drift — mismatched
target/modulesettings betweentsconfig.jsonand your bundler cause confusing errors; keep them aligned.
If your goal is safer JavaScript in a growing codebase, start with a tsconfig.json, enable strict, and convert files incrementally. If you are writing a small script that will not be maintained, plain JavaScript remains the simpler choice.