TypeScript for JavaScript Developers: A Practical Getting Started Guide
Already know JavaScript? Learn TypeScript in the most efficient way. This guide covers types, interfaces, generics, and the key differences that matter for real-world development.
Learn2Code Team
January 25, 2026
Why TypeScript Exists
TypeScript is JavaScript with static types. That single addition solves the most common source of bugs in JavaScript codebases: type errors.
In JavaScript, you discover type bugs at runtime -- when your app crashes in production because someone passed a string where a number was expected. In TypeScript, you discover them at compile time -- before the code ever runs. Your editor underlines the problem while you type.
In 2026, TypeScript is no longer optional for professional web development. Most major companies require it. React, Angular, Next.js, and Deno all use TypeScript extensively. The question is not whether to learn it, but when.
If you already know JavaScript, the answer is now.
What TypeScript Adds to JavaScript
TypeScript is a strict superset of JavaScript. Every valid JavaScript program is also valid TypeScript. TypeScript adds:
- Static type annotations -- declare what types variables, parameters, and return values should be
- Interfaces and type aliases -- define the shape of objects
- Generics -- write reusable code that works with multiple types
- Enums -- define named constants
- Type inference -- TypeScript often figures out types without explicit annotations
The key insight: TypeScript does not add new runtime behavior. It only adds compile-time checks. All TypeScript code compiles down to plain JavaScript.
Your First TypeScript Code
Basic Type Annotations
1// JavaScript2let name = "Alice";3let age = 30;4let isActive = true;5 6// TypeScript -- same thing with explicit types7let name: string = "Alice";8let age: number = 30;9let isActive: boolean = true;In practice, TypeScript infers these basic types automatically. You write explicit annotations when the type is not obvious from the value.
Function Types
This is where TypeScript shines. JavaScript functions accept anything and return anything. TypeScript makes the contract explicit.
1// JavaScript -- what does this return? What types does it accept?2function calculateTax(price, taxRate) {3 return price * taxRate;4}5 6// TypeScript -- the contract is clear7function calculateTax(price: number, taxRate: number): number {8 return price * taxRate;9}10 11// Now this is a compile-time error, not a runtime surprise12calculateTax("100", 0.2); // Error: Argument of type 'string' is not assignable to parameter of type 'number'Arrays
1// Array of strings2let fruits: string[] = ["apple", "banana", "orange"];3 4// Array of numbers5let scores: number[] = [95, 87, 92, 78];6 7// TypeScript catches this8fruits.push(42); // Error: Argument of type 'number' is not assignable to parameter of type 'string'Objects with Interfaces
Interfaces define the shape of objects. They are one of TypeScript's most useful features.
1interface User {2 id: number;3 name: string;4 email: string;5 isAdmin: boolean;6}7 8function greetUser(user: User): string {9 return `Hello, ${user.name}!`;10}11 12// This works13greetUser({ id: 1, name: "Alice", email: "alice@example.com", isAdmin: false });14 15// This fails -- missing required properties16greetUser({ id: 1, name: "Alice" }); // Error: missing email and isAdminOptional Properties
Not every property is always present. Use ? to mark optional properties.
1interface UserProfile {2 name: string;3 email: string;4 bio?: string; // optional5 website?: string; // optional6}7 8// Both are valid9const user1: UserProfile = { name: "Alice", email: "a@b.com" };10const user2: UserProfile = { name: "Bob", email: "b@b.com", bio: "Developer" };Union Types: This OR That
Sometimes a value can be more than one type. Union types handle this.
1// Can be a string or a number2let id: string | number;3id = "abc-123"; // valid4id = 42; // valid5id = true; // Error: Type 'boolean' is not assignable6 7// Useful for function parameters8function formatId(id: string | number): string {9 if (typeof id === "string") {10 return id.toUpperCase();11 }12 return `#${id}`;13}Type Aliases: Name Your Types
Type aliases give names to complex types, making your code more readable.
1type Status = "active" | "inactive" | "suspended";2type UserId = string | number;3 4interface User {5 id: UserId;6 name: string;7 status: Status;8}9 10// TypeScript enforces the exact values11const user: User = {12 id: 1,13 name: "Alice",14 status: "active" // only "active", "inactive", or "suspended" allowed15};Generics: Write Reusable Typed Code
Generics let you write functions and types that work with multiple types while preserving type safety.
1// Without generics -- works but loses type information2function getFirst(items: any[]): any {3 return items[0];4}5 6// With generics -- preserves type information7function getFirst<T>(items: T[]): T {8 return items[0];9}10 11const firstNumber = getFirst([1, 2, 3]); // type: number12const firstString = getFirst(["a", "b", "c"]); // type: stringA common real-world use of generics is API response wrappers:
1interface ApiResponse<T> {2 data: T;3 status: number;4 message: string;5}6 7interface User {8 id: number;9 name: string;10}11 12// The response is typed to contain User data13const response: ApiResponse<User> = {14 data: { id: 1, name: "Alice" },15 status: 200,16 message: "Success"17};Common Utility Types
TypeScript includes built-in utility types that transform existing types.
1interface User {2 id: number;3 name: string;4 email: string;5 isAdmin: boolean;6}7 8// Make all properties optional9type PartialUser = Partial<User>;10 11// Make all properties required12type RequiredUser = Required<User>;13 14// Select specific properties15type UserBasic = Pick<User, "id" | "name">;16 17// Exclude specific properties18type UserWithoutAdmin = Omit<User, "isAdmin">;19 20// Make all properties read-only21type ReadonlyUser = Readonly<User>;These are particularly useful for update functions where you only want to change some fields:
1function updateUser(id: number, updates: Partial<User>): User {2 // Only pass the fields you want to change3 // ...4}5 6updateUser(1, { name: "New Name" }); // valid -- only updating nameMigrating from JavaScript to TypeScript
You do not need to rewrite your entire codebase. TypeScript supports gradual adoption.
Step 1: Rename Files
Change .js files to .ts (or .jsx to .tsx for React). TypeScript will immediately start checking your code and reporting issues.
Step 2: Fix the Easy Errors
Most initial errors are straightforward:
- Add type annotations to function parameters
- Define interfaces for your data structures
- Fix actual bugs that TypeScript caught (these are wins)
Step 3: Use any Sparingly as a Temporary Fix
If a type is too complex to define immediately, you can use any as a temporary escape hatch:
1// Temporary -- come back and type this properly2let complexData: any = fetchData();But treat any as technical debt. Every any is a place where TypeScript cannot help you.
Step 4: Enable Strict Mode Gradually
TypeScript has a strict flag in tsconfig.json that enables all strict type checks. Start with it off, then turn it on once you have typed most of your code.
TypeScript with React
TypeScript and React work together naturally. Here are the most common patterns:
Typing Props
1interface ButtonProps {2 label: string;3 onClick: () => void;4 variant?: "primary" | "secondary";5 disabled?: boolean;6}7 8function Button({ label, onClick, variant = "primary", disabled = false }: ButtonProps) {9 return (10 <button onClick={onClick} disabled={disabled} className={variant}>11 {label}12 </button>13 );14}Typing State
1const [count, setCount] = useState<number>(0);2const [user, setUser] = useState<User | null>(null);3const [items, setItems] = useState<string[]>([]);Typing Events
1function handleChange(event: React.ChangeEvent<HTMLInputElement>) {2 console.log(event.target.value);3}4 5function handleSubmit(event: React.FormEvent<HTMLFormElement>) {6 event.preventDefault();7}Common Mistakes When Starting TypeScript
Mistake 1: Over-typing Everything
TypeScript has excellent type inference. You do not need to annotate everything.
1// Unnecessary -- TypeScript already knows this is a string2const name: string = "Alice";3 4// Better -- let TypeScript infer it5const name = "Alice";Annotate function parameters and return types. Let TypeScript infer the rest.
Mistake 2: Using any Everywhere
If every type is any, you are writing JavaScript with extra syntax. Use unknown instead of any when you genuinely do not know the type -- it forces you to check the type before using the value.
Mistake 3: Ignoring Compiler Errors
TypeScript errors exist to help you. Suppressing them with @ts-ignore or as any defeats the purpose. Fix the underlying type issue instead.
Mistake 4: Not Using Strict Mode
Strict mode catches the most common bugs. Enable it as soon as possible in your tsconfig.json:
1{2 "compilerOptions": {3 "strict": true4 }5}Start Writing TypeScript Today
If you know JavaScript, you already know most of TypeScript. The type system is an addition, not a replacement. Start by:
- Converting one small file from
.jsto.ts - Adding type annotations to function parameters
- Defining interfaces for your main data structures
- Fixing the errors TypeScript finds (many will be real bugs)
Within a week, you will wonder how you ever wrote JavaScript without types.
Practice your TypeScript syntax with our interactive TypeScript exercises and keep our TypeScript cheatsheet bookmarked for quick reference.
Related Reading
- Best Programming Language to Learn First in 2026 -- where TypeScript fits in the language landscape
- React for Beginners: What to Learn First -- TypeScript is commonly used with React in production
- How to Learn JavaScript from Scratch -- master JavaScript fundamentals before adding TypeScript
