- Learn
- Stack Essentials
- TypeScript
- TypeScript for AI Code
Beginner15 min
Learn TypeScript fundamentals to read, understand, and modify AI-generated type-safe code.
TypeScript for AI Code
AI tools generate TypeScript by default. Understanding types helps you read, modify, and debug AI-generated code effectively.
Why AI Tools Use TypeScript
Type Safety Benefits
Terminal
// JavaScript - no type hints
function createUser(name, age, email) {
return { name, age, email }
}
// TypeScript - self-documenting
function createUser(name: string, age: number, email: string): User {
return { name, age, email }
}
AI tools prefer TypeScript because:
- Self-documenting - Types explain what code expects
- Error prevention - Catches bugs before runtime
- Better autocomplete - IDE suggestions are more accurate
- Refactoring safety - Changes propagate correctly
What You'll See
AI-generated code includes:
Terminal
// Type annotations
const count: number = 0
const name: string = "John"
// Interface definitions
interface User {
id: string
name: string
email: string
}
// Generic types
const items: Array<User> = []
// Function types
const handleClick: (e: React.MouseEvent) => void
Basic Type Annotations
Primitive Types
Terminal
// String
const name: string = "Alice"
// Number (integers and floats)
const age: number = 25
const price: number = 99.99
// Boolean
const isActive: boolean = true
// Array
const numbers: number[] = [1, 2, 3]
const names: string[] = ["a", "b", "c"]
// Alternative array syntax
const items: Array<string> = ["x", "y", "z"]
Type Inference
TypeScript often infers types automatically:
Terminal
// TypeScript knows these types
const name = "Alice" // string
const count = 42 // number
const active = true // boolean
const items = [1, 2, 3] // number[]
// No need to write:
const name: string = "Alice" // redundant
AI tools may include explicit types for clarity, but inference works fine.
Union Types
Variables that can be multiple types:
Terminal
// Can be string or number
let id: string | number
id = "abc123"
id = 12345
// Common pattern: nullable values
let name: string | null = null
name = "Alice"
// Optional chaining works with these
const length = name?.length
Literal Types
Specific values as types:
Terminal
// Can only be these exact strings
type Status = "pending" | "active" | "inactive"
let status: Status = "pending"
status = "active" // OK
status = "unknown" // Error!
// Common in component props
type Size = "sm" | "md" | "lg"
type Variant = "default" | "outline" | "ghost"
Interfaces and Types
Defining Object Shapes
Terminal
// Interface - preferred for objects
interface User {
id: string
name: string
email: string
age?: number // Optional property
}
// Type alias - also works
type Product = {
id: string
name: string
price: number
}
Using Interfaces
Terminal
interface User {
id: string
name: string
email: string
}
// Function parameter
function getUser(id: string): User {
return { id, name: "Alice", email: "alice@example.com" }
}
// Array of objects
const users: User[] = [
{ id: "1", name: "Alice", email: "alice@example.com" },
{ id: "2", name: "Bob", email: "bob@example.com" },
]
// Component props
interface ButtonProps {
children: React.ReactNode
onClick?: () => void
disabled?: boolean
}
function Button({ children, onClick, disabled }: ButtonProps) {
return <button onClick={onClick} disabled={disabled}>{children}</button>
}
Extending Interfaces
Terminal
// Base interface
interface BaseEntity {
id: string
createdAt: Date
updatedAt: Date
}
// Extend with additional properties
interface User extends BaseEntity {
name: string
email: string
}
// User now has: id, createdAt, updatedAt, name, email
Optional vs Required
Terminal
interface UserProfile {
// Required properties
id: string
name: string
email: string
// Optional properties (?)
age?: number
bio?: string
avatarUrl?: string
}
// Valid - optional properties omitted
const user: UserProfile = {
id: "1",
name: "Alice",
email: "alice@example.com"
}
Function Types
Parameter and Return Types
Terminal
// Basic function
function add(a: number, b: number): number {
return a + b
}
// Arrow function
const multiply = (a: number, b: number): number => a * b
// Return type inference (often omitted)
const divide = (a: number, b: number) => a / b // infers number
Void and Never
Terminal
// void - function doesn't return anything
function logMessage(message: string): void {
console.log(message)
}
// Event handlers typically return void
const handleClick = (e: React.MouseEvent): void => {
e.preventDefault()
}
// never - function never returns (throws or infinite loop)
function throwError(message: string): never {
throw new Error(message)
}
Optional Parameters
Terminal
// Optional parameter with ?
function greet(name: string, greeting?: string): string {
return `${greeting || "Hello"}, ${name}!`
}
greet("Alice") // "Hello, Alice!"
greet("Alice", "Hi") // "Hi, Alice!"
// Default parameter
function greet(name: string, greeting: string = "Hello"): string {
return `${greeting}, ${name}!`
}
Callback Types
Terminal
// Function as parameter
function fetchData(callback: (data: User[]) => void): void {
// ...
callback(users)
}
// Common React patterns
interface ButtonProps {
onClick?: () => void
onSubmit?: (data: FormData) => Promise<void>
onChange?: (value: string) => void
}
Generics Basics
What Are Generics?
Generics create reusable components that work with multiple types:
Terminal
// Without generics - only works with numbers
function firstNumber(arr: number[]): number {
return arr[0]
}
// With generics - works with any type
function first<T>(arr: T[]): T {
return arr[0]
}
first([1, 2, 3]) // returns number
first(["a", "b", "c"]) // returns string
first([{ id: 1 }]) // returns object
Common Generic Patterns
Terminal
// Array
const items: Array<string> = ["a", "b"]
// Promise
const data: Promise<User> = fetchUser()
// Record (object with known key/value types)
const scores: Record<string, number> = {
alice: 100,
bob: 85
}
// Partial (all properties optional)
const update: Partial<User> = { name: "New Name" }
// Pick (subset of properties)
type UserPreview = Pick<User, "id" | "name">
// Omit (exclude properties)
type UserWithoutEmail = Omit<User, "email">
React Component Generics
Terminal
// Generic component
interface ListProps<T> {
items: T[]
renderItem: (item: T) => React.ReactNode
}
function List<T>({ items, renderItem }: ListProps<T>) {
return <ul>{items.map(renderItem)}</ul>
}
// Usage
<List
items={users}
renderItem={(user) => <li key={user.id}>{user.name}</li>}
/>
Reading AI-Generated Types
Common Patterns
Terminal
// Props interface
interface PageProps {
params: { slug: string }
searchParams: { [key: string]: string | string[] | undefined }
}
// Component with props
export default function Page({ params, searchParams }: PageProps) {
// ...
}
// API response type
interface ApiResponse<T> {
data: T
error: string | null
loading: boolean
}
// Hook return type
function useUser(id: string): {
user: User | null
loading: boolean
error: Error | null
} {
// ...
}
React Types
Terminal
// Event types
onClick: (e: React.MouseEvent<HTMLButtonElement>) => void
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void
onSubmit: (e: React.FormEvent<HTMLFormElement>) => void
// Children types
children: React.ReactNode // Most flexible
children: React.ReactElement // Single element
children: string // Text only
// Ref types
const inputRef = useRef<HTMLInputElement>(null)
const divRef = useRef<HTMLDivElement>(null)
// State types
const [count, setCount] = useState<number>(0)
const [user, setUser] = useState<User | null>(null)
HTML Element Props
Terminal
// Extend HTML element props
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: "default" | "outline"
size?: "sm" | "md" | "lg"
}
// All HTML button props available (onClick, disabled, type, etc.)
function Button({ variant, size, ...props }: ButtonProps) {
return <button {...props} />
}
Type Errors
Common Errors and Fixes
Property doesn't exist:
Terminal
// Error: Property 'name' does not exist on type '{}'
const user = {}
console.log(user.name)
// Fix: Define the type
const user: User = { id: "1", name: "Alice", email: "a@b.com" }
Type mismatch:
Terminal
// Error: Type 'string' is not assignable to type 'number'
const age: number = "25"
// Fix: Use correct type
const age: number = 25
// or
const age = parseInt("25")
Possibly null:
Terminal
// Error: Object is possibly 'null'
const user = users.find(u => u.id === id)
console.log(user.name) // user might be undefined
// Fix: Check for null
if (user) {
console.log(user.name)
}
// or use optional chaining
console.log(user?.name)
Missing properties:
Terminal
// Error: Property 'email' is missing
const user: User = {
id: "1",
name: "Alice"
// missing email!
}
// Fix: Add required property
const user: User = {
id: "1",
name: "Alice",
email: "alice@example.com"
}
Type Assertions
When TypeScript Needs Help
Terminal
// You know more than TypeScript
const input = document.getElementById("email") as HTMLInputElement
input.value = "test@example.com"
// Non-null assertion (use carefully!)
const user = users.find(u => u.id === id)!
console.log(user.name) // Trust that it exists
// Type narrowing is usually better
const user = users.find(u => u.id === id)
if (!user) throw new Error("User not found")
console.log(user.name) // TypeScript knows it's defined
Summary
- Type annotations:
name: string,count: number - Interfaces: Define object shapes
- Union types:
string | null,"a" | "b" | "c" - Optional:
property?: type - Generics:
Array<T>,Promise<T> - Type inference: Let TypeScript figure out types when obvious
Next Steps
Learn common TypeScript patterns used in AI-generated React and Next.js code.
Mark this lesson as complete to track your progress