A TypeScript interface defines the shape data must conform to — which properties exist, and their types — purely as a compile-time construct that catches type mismatches during development and disappears entirely from the final compiled JavaScript.
Defining a basic interface
interface Product {
id: number;
name: string;
price: number;
inStock: boolean;
}
Using it to type a variable or function parameter
const product: Product = {
id: 1,
name: 'Widget',
price: 19.99,
inStock: true,
};
function displayProduct(product: Product): string {
return `${product.name} — $${product.price}`;
}
Assigning an object missing a required property, or with a mismatched type, produces a compile-time TypeScript error — this is the actual value an interface provides, catching mistakes before the code ever runs rather than surfacing as a runtime bug.
Optional properties
interface Product {
id: number;
name: string;
price: number;
description?: string; // optional — the ? marks it as not required
}
Typing an HTTP service's response with an interface
@Injectable({ providedIn: 'root' })
export class ProductService {
constructor(private http: HttpClient) {}
getProducts(): Observable {
return this.http.get('/api/products');
}
}
Typing the HTTP response with the interface (Observable) gives autocomplete and compile-time type checking on every property accessed from the API response throughout the component consuming this service.
Extending an interface
interface Product {
id: number;
name: string;
price: number;
}
interface DetailedProduct extends Product {
description: string;
specifications: Record;
}
Extending an interface builds a more specific shape on top of a shared base — useful when a detail view needs additional fields beyond what a summary list view requires from the same underlying entity.
Interface vs. class: the key practical difference
interface ProductInterface {
id: number;
name: string;
}
class ProductClass {
constructor(public id: number, public name: string) {}
}
An interface exists only at compile time and produces zero runtime JavaScript — a class, by contrast, compiles to a real, instantiable JavaScript constructor function. Use an interface purely for typing plain data shapes (like an API response); use a class when the type also needs actual behavior (methods) or needs to be instantiated with new.
Using type aliases as an alternative to interfaces
type Product = {
id: number;
name: string;
price: number;
};
A type alias can express nearly the same thing as an interface for a plain object shape — interfaces are generally preferred by convention for object shapes specifically because they support declaration merging and are slightly more idiomatic in most Angular style guides, though the practical difference for a simple data shape like this is minor.