How structural typing differs from nominal typing in Typescript - Performance & Efficiency
We want to understand how checking if two types match grows in cost as types get bigger or more complex.
How does the way TypeScript compares types affect the work it does?
Analyze the time complexity of type compatibility checks in TypeScript's structural typing.
interface Point {
x: number;
y: number;
}
interface NamedPoint {
x: number;
y: number;
name: string;
}
let p: Point = { x: 1, y: 2 };
const np: NamedPoint = { x: 1, y: 2, name: "A" };
// Structural typing allows this:
p = np;
This code shows TypeScript allowing assignment based on matching properties, not explicit names.
When TypeScript checks if one type fits another, it compares each property.
- Primary operation: Comparing each property in the source and target types.
- How many times: Once for each property in the target type.
As the number of properties in the types grows, the work to check compatibility grows too.
| Input Size (n properties) | Approx. Operations |
|---|---|
| 10 | 10 property comparisons |
| 100 | 100 property comparisons |
| 1000 | 1000 property comparisons |
Pattern observation: The checking work grows directly with the number of properties.
Time Complexity: O(n)
This means the time to check types grows in a straight line with the number of properties.
[X] Wrong: "TypeScript compares types by their names, so checking is instant."
[OK] Correct: TypeScript compares the shape (properties) of types, so it must check each property, which takes time.
Understanding how TypeScript checks types helps you explain how your code scales and why some checks take longer with bigger types.
What if TypeScript used nominal typing instead of structural typing? How would the time complexity of type checks change?
Practice
structural typing in TypeScript?Solution
Step 1: Understand structural typing concept
Structural typing means compatibility depends on the shape (properties and types) of objects, not their names.Step 2: Compare with nominal typing
Nominal typing requires exact type names or declarations to match, which is not how TypeScript works by default.Final Answer:
Types are compatible if their properties and types match, regardless of their names. -> Option AQuick Check:
Structural typing = shape-based compatibility [OK]
- Confusing structural typing with nominal typing
- Thinking type names must match for compatibility
- Assuming runtime checks for type compatibility
Solution
Step 1: Check property shapes for compatibility
const a: {name: string} = {name: 'Alice'}; const b: {name: string} = a; assigns an object with a matching propertyname: stringto another variable with the same shape, which is allowed.Step 2: Analyze other options for incompatibility
A mismatches properties (id vs name), B uses classes (nominal typing), D mismatches property types.Final Answer:
const a: {name: string} = {name: 'Alice'}; const b: {name: string} = a; -> Option AQuick Check:
Matching shapes = compatible [OK]
- Assuming different property names are compatible
- Ignoring property type mismatches
- Confusing class inheritance with structural typing
interface Point { x: number; y: number; }
interface Named { name: string; }
const p: Point = { x: 10, y: 20 };
const n: Named = { name: 'Origin' };
function printPoint(point: Point) {
console.log(`x=${point.x}, y=${point.y}`);
}
printPoint(p);
printPoint(n as unknown as Point);Solution
Step 1: Understand structural typing and casting
The objectpmatchesPointshape, soprintPoint(p)prints x=10, y=20. The objectndoes not havexory, but is forced cast toPoint.Step 2: Predict output for forced cast
At runtime,nlacksxandy, so accessing them printsundefined.Final Answer:
x=10, y=20 x=undefined, y=undefined -> Option BQuick Check:
Forced cast ignores shape, runtime undefined properties [OK]
- Expecting runtime type errors
- Assuming cast adds missing properties
- Confusing property names with values
interface A { id: number; }
interface B { id: number; name: string; }
const a: A = { id: 1 };
const b: B = a;Solution
Step 1: Check property requirements for assignment
Variablebexpects an object withidandname. Variableaonly hasid.Step 2: Understand structural typing rules
Structural typing requires the assigned object to have at least the required properties. Here,ais missingname, so assignment fails.Final Answer:
Error becausealacks propertynamerequired byB. -> Option DQuick Check:
Missing required properties cause assignment error [OK]
- Ignoring missing properties in assignment
- Thinking interface names must match for compatibility
- Assuming partial property match is enough
class Person { name: string; constructor(name: string) { this.name = name; } }
class Employee { name: string; salary: number; constructor(name: string, salary: number) { this.name = name; this.salary = salary; } }
let p: Person = new Person('Alice');
let e: Employee = new Employee('Bob', 50000);
// Which assignment is valid?
// 1) p = e;
// 2) e = p;Solution
Step 1: Compare properties of Person and Employee
Person hasname. Employee hasnameandsalary. Employee has all Person properties plus more.Step 2: Apply structural typing rules for assignment
Assigninge(Employee) top(Person) is allowed becauseehas at least the properties ofp. The reverse is not allowed becauseplackssalary.Final Answer:
Only assignment 1) p = e; is allowed because Employee has all Person properties. -> Option CQuick Check:
Subtype with extra properties can assign to supertype [OK]
- Assuming both assignments are allowed
- Confusing nominal typing with structural typing here
- Ignoring extra properties in assignment compatibility
Ready to prove it?
Pass the test and this pattern moves unknown
