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

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)