# 10 TypeScript Types Every Frontend Dev Should Know


A lot of TypeScript usage stops at basic annotations — `string`, `number`, `boolean` — and stays there. That's fine for simple cases, but it means missing the type features that catch real bugs before they ship. Here are 10 worth actually knowing.

**1. Union types** — a value that can be one of several types.
```typescript
type Status = 'idle' | 'loading' | 'success' | 'error';
```
Better than a generic `string` — TypeScript will catch a typo like `'sucess'` immediately.

**2. Interfaces vs Type aliases** — both describe object shapes; interfaces can be extended/merged, type aliases can represent unions and primitives too.
```typescript
interface User { name: string; age: number; }
type ID = string | number;
```
Rule of thumb: interfaces for object shapes that might be extended, type aliases for everything else.

**3. Generics** — write reusable code that works with multiple types while keeping type safety.
```typescript
function firstItem<T>(arr: T[]): T {
  return arr[0];
}
```
Without generics, you'd either lose type safety (`any`) or duplicate the function per type.

**4. Optional and readonly properties**
```typescript
interface Config {
  timeout?: number;
  readonly apiKey: string;
}
```
`?` marks a property as optional; `readonly` prevents reassignment after creation — genuinely useful for props that shouldn't change after initialization.

**5. Utility types: Partial, Pick, Omit**
```typescript
type PartialUser = Partial<User>;       // all properties optional
type NameOnly = Pick<User, 'name'>;     // only the 'name' property
type WithoutAge = Omit<User, 'age'>;    // everything except 'age'
```
These derive new types from existing ones instead of manually rewriting similar interfaces — reducing duplication when types are related but not identical.

**6. Type guards** — narrow a type within a conditional block.
```typescript
function isString(value: unknown): value is string {
  return typeof value === 'string';
}
```
Especially useful with `unknown` (safer than `any`) — you can't use a value until you've proven its type.

**7. Discriminated unions** — a pattern for modeling state that can be one of several distinct shapes.
```typescript
type Result =
  | { status: 'success'; data: string }
  | { status: 'error'; message: string };
```
TypeScript narrows the type automatically based on the `status` field, which eliminates a whole category of "accessing a property that doesn't exist on this branch" bugs.

**8. Mapped types** — transform an existing type's properties.
```typescript
type Readonly<T> = { readonly [K in keyof T]: T[K] };
```
Advanced, but this is how many built-in utility types (like `Partial` and `Readonly`) are actually implemented under the hood.

**9. `unknown` vs `any`**
`any` disables type checking entirely. `unknown` also accepts anything, but forces you to narrow the type before using it — meaningfully safer for values from external sources (API responses, user input).

**10. Template literal types** — build string types from patterns.
```typescript
type EventName = `on${Capitalize<'click' | 'hover'>}`;
// 'onClick' | 'onHover'
```
Useful for enforcing naming conventions at the type level, especially in prop interfaces for component libraries.

**Why this matters beyond "fewer bugs":**

Good types are documentation that can't go stale. A discriminated union tells the next developer exactly what shapes are possible without needing a comment — and the compiler enforces it stays accurate as the code changes.

**Takeaway:** If your TypeScript usage is mostly basic type annotations, you're using it as a linter, not a design tool. Union types, generics, and discriminated unions specifically are where TypeScript starts catching real logic errors, not just typos.
