TypeScript Type Inference & Aliases
TypeScript can automatically infer types from context. Type aliases let you name and reuse complex types.
Type Inference
TypeScript determines the type from the assigned value:
let name = "John"; // inferred: string
let age = 25; // inferred: number
let isActive = true; // inferred: boolean
value = 42; // Error: Type 'number' is not assignable to type 'string'
Remember: Once inferred, the type is fixed for that variable.
When Inference Fails
Without an initial value, TypeScript defaults to any:
let value; // type: any
let emptyArray = []; // type: any[]
Tip: Always initialize variables or add annotations to help TypeScript.
Type Aliases
Give a name to any type for reuse:
type StringOrNumber = string | number;
let id: StringOrNumber = "abc123";
id = 42; // OK
id = true; // Error
type User = {
name: string;
age: number;
};
let user: User = { name: "John", age: 25 };
Why aliases? Make complex types readable and reusable.
Function Type Aliases
Reuse function signatures:
type AddFn = (a: number, b: number) => number;
const add: AddFn = (a, b) => a + b;
Literal Types
Restrict values to specific options:
type Direction = "north" | "south" | "east" | "west";
let dir: Direction = "north";
// dir = "up"; // Error
type Status = "pending" | "approved" | "rejected";
Tip: Use literal types instead of magic strings.
Template Literal Types
Combine string literals with template syntax:
type EventName = `on${string}`;
let handler: EventName = "onClick"; // OK
// let error: EventName = "fetch"; // Error: doesn't start with 'on'
Best Practices
- Let TypeScript infer types when possible
- Initialize variables to help inference
- Use type aliases for complex or repeated types
- Prefer literal types for fixed sets of values
Common Mistakes
- Uninitialized variables default to
any - Overusing type aliases — consider interfaces for objects
- Empty arrays without type annotation =
any[] - Confusing type aliases and interfaces — use aliases for unions, interfaces for objects