- Describe an object's shape with
interfaceandtype - Use optional (
?) and read-only (readonly) properties - Extend an interface with
extends - Explain the difference between
interfaceandtype, and structural typing
In a school's online gradebook, a student object travels through dozens of functions: it is added to a list, its marks are calculated, it is shown on the screen. Every time the same question comes up: which properties does this object have? grade or class? Is there always an email? In TypeScript you describe the object's shape once and reuse that description everywhere — and the compiler makes sure it is followed.
Describing an object's shape
A named type that describes which properties an object must have and what their types are. It is declared with the keyword interface and produces no JavaScript at all — it exists only for checking.
interface Student {
readonly id: number;
name: string;
grade: number;
email?: string;
}
const aysel: Student = { id: 1, name: 'Aysel', grade: 9 };
const murad: Student = { id: 2, name: 'Murad', grade: 10, email: 'murad@example.com' };
function describe(s: Student): string {
const contact = s.email ?? 'no email';
return `#${s.id} ${s.name}, grade ${s.grade} (${contact})`;
}
console.log(describe(aysel));
console.log(describe(murad));#1 Aysel, grade 9 (no email) #2 Murad, grade 10 (murad@example.com)
email?: stringis an optional property: the object may not have it, and when you read it, its type isstring | undefined. That is why we gave a fallback with??.readonly id: numberis a read-only property: it is set when the object is created and can't be changed afterwards.- Properties are separated by semicolons or commas; their order doesn't matter.
Now let's try to break the contract: forget a property, add an extra one and change a readonly field.
interface Student {
readonly id: number;
name: string;
grade: number;
}
const leyla: Student = { id: 3, name: 'Leyla' };
const elvin: Student = { id: 4, name: 'Elvin', grade: 8, age: 14 };
elvin.id = 5;students.ts:7:7 - error TS2741: Property 'grade' is missing in type '{ id: number; name: string; }' but required in type 'Student'.
7 const leyla: Student = { id: 3, name: 'Leyla' };
~~~~~
students.ts:4:3
4 grade: number;
~~~~~
'grade' is declared here.
students.ts:8:58 - error TS2353: Object literal may only specify known properties, and 'age' does not exist in type 'Student'.
8 const elvin: Student = { id: 4, name: 'Elvin', grade: 8, age: 14 };
~~~
students.ts:9:7 - error TS2540: Cannot assign to 'id' because it is a read-only property.
9 elvin.id = 5;
~~TS2741), an extra property (TS2353) and an assignment to a readonly field (TS2540).Extending and type aliases
An interface can extend another interface with extends — like inheritance in classes: Teacher gets all of Person's properties and adds its own. A type alias, on the other hand, gives a name to any type with the keyword type: an object, a union, a tuple, even a primitive.
interface Person {
name: string;
}
interface Teacher extends Person {
subject: string;
}
type Point = { x: number; y: number };
type ID = number | string;
const teacher: Teacher = { name: 'Elvin', subject: 'Physics' };
const start: Point = { x: 0, y: 0 };
const code: ID = 'A-17';
console.log(`${teacher.name} teaches ${teacher.subject}`);
console.log(start, code);Elvin teaches Physics
{ x: 0, y: 0 } A-17ID can be either a number or a string — we will study such unions in detail in the next lesson.interface or type?
| Feature | interface | type |
|---|---|---|
| Describe an object's shape | ✓ | ✓ |
| Extend | extends | & (intersection) |
| Name a union, a tuple or a primitive | ✗ | ✓ |
| Re-declare with the same name to merge | ✓ | ✗ |
interface declarations with the same name merge automatically (declaration merging); two type declarations with the same name are an error.Structural typing
TypeScript compares types by their structure, not by their names. If an object has the required properties, it fits the type — no matter how it was created. The extra-property error (TS2353) only appears when an object is written directly as a literal, because there an extra property is most likely a typo.
interface Named {
name: string;
}
function hello(thing: Named): string {
return `Hello, ${thing.name}!`;
}
const dog = { name: 'Rex', legs: 4 };
console.log(hello(dog));
console.log(hello({ name: 'Baku' }));Hello, Rex! Hello, Baku!
dog was never declared as Named and has an extra legs property, but it fits because it has a name.Key points
interfaceandtypedescribe which properties and types an object has; they produce no JavaScript.prop?: Tis an optional property;readonly prop: Tcan't be changed after creation.- An interface is extended with
extends;typecan name any type, including a union. - The compiler catches missing properties (
TS2741) and extra properties in literals (TS2353). - TypeScript uses structural typing: if the shape fits, the name doesn't matter.
Check yourself
10 questions. Every correct answer earns XP.
email?: string mean in an interface?