What are types, interfaces, and type annotations in TypeScript?
Updated Feb 20, 2026
Short answer
Types, interfaces, and type annotations are TypeScript features that add static type checking to JavaScript. A type annotation explicitly declares the expected type of a variable, function parameter, or return value, while type aliases and interface declarations define reusable custom types. They help catch errors early, improve code readability, and provide better tooling support through autocomplete and refactoring.
Deep explanation
TypeScript is a superset of JavaScript that adds a static type system. JavaScript determines types at runtime, but TypeScript checks types during development and compilation.
Type Annotations
A type annotation tells TypeScript what type a value should have. It is written after a variable, parameter, or return value using a colon (:).
Example:
let username: string = "Alice";let age: number = 25;let isActive: boolean = true;If a value of the wrong type is assigned, TypeScript reports an error:
let age: number = "twenty";// Error: Type 'string' is not assignable to type 'number'Type annotations can also be used with functions:
function add(a: number, b: number): number { return a + b;}Here:
a: numberspecifies the parameter types.b: numberspecifies the parameter types.: numberafter the parentheses specifies the return type.
TypeScript can often infer types automatically:
let message = "Hello";TypeScript understands that message is a string, so an annotation is not always required.
let message: string = "Hello";Both versions are valid, but the inferred version is usually preferred when the type is obvious.
---
Type Aliases (type)
A type alias creates a custom name for an existing type. It is useful for making complex types easier to reuse.
Example:
type User = { id: number; name: string; email: string;};
const user: User = { id: 1, name: "Alice", email: "alice@example.com"};The User type describes the expected structure of a user object.
Type aliases can represent more than objects. They can define unions, primitives, tuples, and other combinations:
type ID = string | number;
let userId: ID;
userId = "abc123";userId = 456;A union type means a value can be one of multiple allowed types.
Another example:
type Status = "pending" | "success" | "error";
let requestStatus: Status = "success";Only the listed string values are allowed.
---
Interfaces
An interface defines the shape of an object. It describes what properties and methods an object should have.
Example:
interface User { id: number; name: string; email: string;}
const user: User = { id: 1, name: "Alice", email: "alice@example.com"};Interfaces are commonly used for object-oriented designs and public APIs.
Interfaces support extension through inheritance:
interface Person { name: string;}
interface Employee extends Person { employeeId: number;}
const employee: Employee = { name: "Bob", employeeId: 1001};The Employee interface includes all properties from Person plus its own properties.
---
Differences Between type and interface
For many object shapes, type and interface can be used interchangeably:
interface Product { id: number; price: number;}
type ProductType = { id: number; price: number;};Both describe the same object structure.
However, there are some differences:
| Feature | interface | type |
|---|---|---|
| Object shapes | Yes | Yes |
| Extending types | extends | Intersection (&) |
| Union types | No | Yes |
| Primitive aliases | No | Yes |
| Declaration merging | Yes | No |
Example of a type union:
type Result = string | number;This cannot be represented with an interface.
Example of interface declaration merging:
interface User { name: string;}
interface User { age: number;}
const user: User = { name: "Alice", age: 25};TypeScript combines both interface declarations into one.
---
Why Use Types and Interfaces?
They provide several benefits:
- Early error detection: Problems are caught before running the application.
- Better editor support: Editors can provide autocomplete and better navigation.
- Clear contracts: Developers understand what data structures functions expect.
- Safer refactoring: Changing a type can reveal all affected parts of a codebase.
- Improved maintainability: Large projects become easier to understand.
---
Optional and Readonly Properties
Types and interfaces can define optional properties using ?:
interface User { id: number; name: string; phone?: string;}A User object may or may not have a phone property.
Properties can also be marked as readonly:
interface Config { readonly apiUrl: string;}
const config: Config = { apiUrl: "https://example.com"};
config.apiUrl = "new-url";// Error: Cannot assign to 'apiUrl' because it is read-only---
Real-world example
A frontend application might receive user data from an API. Defining a type ensures that components know what data is available:
interface UserProfile { id: number; username: string; avatarUrl?: string; roles: string[];}
function displayUser(user: UserProfile): string { return `Welcome, ${user.username}`;}
const profile: UserProfile = { id: 1, username: "alex", roles: ["admin"]};
console.log(displayUser(profile));Without the interface, a developer might accidentally use a property that does not exist:
function displayUser(user: UserProfile) { return user.fullName; // Error: Property 'fullName' does not exist}The type definition acts as a contract between the API data and the application code.
Common mistakes
- * Using `any` everywhere instead of defining meaningful types.
- * Adding unnecessary type annotations when TypeScript can already infer the type.
- * Confusing TypeScript types with JavaScript runtime values
- types are removed after compilation.
- * Using interfaces when a union type or complex type composition is required.
- * Assuming interfaces and type aliases are completely identical in all situations.
- * Defining overly strict types that make normal code changes difficult.
- * Forgetting optional properties when an object field may not always exist.
- * Using type assertions to silence errors instead of fixing incorrect type definitions.
Follow-up questions
- What is the difference between interface and type in TypeScript?
- What is type inference in TypeScript?
- When should you use an interface instead of a type alias?
- What are union and intersection types?
- Are TypeScript types available at runtime?