Understanding TypeScript Types
Learn how TypeScript helps catch errors and makes your code more reliable through type safety.
What You'll Learn
- Why TypeScript matters
- Basic type annotations
- Interfaces and types
- Common TypeScript patterns
- Fixing type errors
Why TypeScript?
Catches Errors Early
JavaScript (errors at runtime):
function greet(name) {
return name.toUppercase(); // Typo! Crashes when called
}
TypeScript (errors in editor):
function greet(name: string) {
return name.toUppercase(); // Red squiggle! Editor shows error
// ^^^^^^^^^^^ Property 'toUppercase' does not exist
}
Better Autocomplete
TypeScript knows what properties and methods are available:
const user = { name: 'Alice', age: 25 };
user. // Editor shows: name, age (autocomplete!)
Basic Types
Primitives
let name: string = 'Alice';
let age: number = 25;
let isStudent: boolean = true;
Arrays
let numbers: number[] = [1, 2, 3];
let names: string[] = ['Alice', 'Bob'];
let mixed: (string | number)[] = [1, 'two', 3];
Objects
let user: {
name: string;
age: number;
} = {
name: 'Alice',
age: 25
};
Interfaces
Defining Interfaces
interface User {
name: string;
email: string;
age?: number; // Optional (?)
}
const user: User = {
name: 'Alice',
email: 'alice@example.com',
// age is optional, can omit
};
Using with Props
interface ButtonProps {
text: string;
onClick: () => void;
disabled?: boolean;
}
export default function Button({ text, onClick, disabled }: ButtonProps) {
return (
<button onClick={onClick} disabled={disabled}>
{text}
</button>
);
}
Common Patterns
Union Types
Value can be one of several types:
type Status = 'idle' | 'loading' | 'success' | 'error';
const [status, setStatus] = useState<Status>('idle');
Type for Props
type AlertType = 'success' | 'warning' | 'error';
interface AlertProps {
type: AlertType;
message: string;
}
Optional Properties
interface CardProps {
title: string; // Required
subtitle?: string; // Optional
image?: string; // Optional
}
Array of Objects
interface NavItem {
name: string;
href: string;
}
const navItems: NavItem[] = [
{ name: 'Home', href: '/' },
{ name: 'About', href: '/about' },
];
Function Types
interface FormProps {
onSubmit: (data: FormData) => void;
onCancel?: () => void;
}
Children Prop
interface LayoutProps {
children: React.ReactNode;
title?: string;
}
export default function Layout({ children, title }: LayoutProps) {
return <div>{children}</div>;
}
React-Specific Types
Component Props
interface ComponentProps {
title: string;
children: React.ReactNode;
}
export default function Component({ title, children }: ComponentProps) {
return <div>{children}</div>;
}
Event Handlers
// Click event
const handleClick = (e: React.MouseEvent) => {
console.log(e);
};
// Form submit
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
};
// Input change
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
console.log(e.target.value);
};
State
const [count, setCount] = useState<number>(0);
const [name, setName] = useState<string>('');
const [user, setUser] = useState<User | null>(null);
Fixing Type Errors
Error: "Type 'X' is not assignable to type 'Y'"
// ❌ Error
let age: number = '25'; // string not assignable to number
// ✅ Fix
let age: number = 25;
Error: "Property 'X' does not exist"
// ❌ Error
interface User {
name: string;
}
const user: User = { name: 'Alice', age: 25 };
// ^^^ Error
// ✅ Fix: Add to interface
interface User {
name: string;
age: number;
}
Error: "Argument of type 'X' is not assignable"
// ❌ Error
function greet(name: string) {
console.log(name);
}
greet(123); // number not assignable to string
// ✅ Fix
greet('Alice');
Quick Fixes
Use any (Last Resort)
// When you really don't know the type
let data: any = someComplexData;
⚠️ Avoid any when possible - defeats the purpose of TypeScript!
Type Assertion
const input = document.getElementById('email') as HTMLInputElement;
input.value = 'test@example.com';
Optional Chaining
// Safe access to nested properties
const city = user?.address?.city;
Nullish Coalescing
// Use default if null/undefined
const name = user.name ?? 'Anonymous';
Common Interfaces in Our Codebase
Nav Item
interface NavItem {
name: string;
href: string;
}
Page Props
interface PageProps {
params: Promise<{
slug: string;
}>;
}
Metadata
import { Metadata } from 'next';
export const metadata: Metadata = {
title: 'Page Title',
description: 'Page description',
};
Best Practices
1. Define Interfaces for Props
// ✅ Good
interface Props {
title: string;
}
// ❌ Bad
function Component(props: any) {
2. Use Descriptive Names
// ✅ Good
interface UserProfileProps {
user: User;
}
// ❌ Bad
interface Props {
data: any;
}
3. Mark Optional Props
interface Props {
required: string;
optional?: string; // Use ?
}
4. Avoid any
// ✅ Good
const data: unknown = apiResponse;
// ❌ Bad
const data: any = apiResponse;
Quick Reference
Basic types:
string, number, boolean, null, undefined
Interface:
interface User {
name: string;
age?: number;
}
Union type:
type Status = 'idle' | 'loading' | 'success';
Array:
string[], number[], User[]
Function:
(param: string) => void
Children:
children: React.ReactNode
Event:
React.MouseEvent, React.FormEvent, React.ChangeEvent
What's Next
Congratulations! You've completed Chapter 08 and learned advanced topics. You're now ready to build real features!
Continue exploring:
- Chapter 09: Troubleshooting (coming soon)
- Chapter 10: Reference (coming soon)