Q1 of 38 · TypeScript
What is the difference between interface and type alias?
Short answer
Short answer: Both define object shapes, but they differ in key ways: interfaces support declaration merging and are preferred for public contracts classes implement; type aliases handle unions, intersections, and mapped/conditional types. For plain object shapes in test code, either works — consistency matters more than the choice.
Detail
The surface syntax looks nearly identical:
interface User { id: number; name: string; }
type User = { id: number; name: string; };
Declaration merging is the clearest functional difference. You can declare the same interface multiple times and TypeScript merges the declarations — useful for augmenting library types (e.g., extending the global Window interface for test utilities). type aliases cannot be merged; a duplicate declaration is a compile error.
Expressiveness: type aliases can represent things that interface cannot:
- Union types:
type Status = "pass" | "fail" | "skip" - Intersection types:
type AdminUser = User & AdminRole - Mapped types:
type Optional<T> = { [K in keyof T]?: T[K] } - Conditional types:
type NonNullable<T> = T extends null | undefined ? never : T
In test code, the practical guidance: use interface when defining the shape of objects that consumers will implement or extend (Page Objects, fixture contracts, service adapters). Use type for unions, utility compositions, and internal helpers. Codebase consistency matters more than the preference — pick one for plain object shapes and stick to it. Most modern TypeScript style guides (including the TypeScript team's own) say interface for extendable shapes, type for everything else.
// EXAMPLE
interface-vs-type.ts
// interface — Page Object contract (classes implement this)
interface LoginPage {
navigate(): Promise<void>;
fillCredentials(email: string, password: string): Promise<void>;
submit(): Promise<void>;
getErrorMessage(): Promise<string>;
}
// type — for unions and utility compositions
type TestLevel = "smoke" | "regression" | "e2e" | "contract";
type TestResult = { passed: boolean; duration: number; error?: string };
// Declaration merging (interface only — augment a library type)
interface Window {
__test_flags__: Record<string, boolean>;
}
// Mapped type — only possible with type alias
type Partial<T> = { [K in keyof T]?: T[K] };
// Intersection — also only type
type AuthenticatedPage = LoginPage & { logout(): Promise<void> };// MODEL ANSWER
// WHAT INTERVIEWERS LOOK FOR
// COMMON PITFALL
// Related questions
What is TypeScript, and what advantages does it offer over plain JavaScript for test automation?
TypeScript
How does TypeScript's type inference work, and when should you add explicit type annotations?
TypeScript
When would you keep a test automation project in plain JavaScript rather than migrating to TypeScript?
JavaScript