Structural typing in TypeScript
Compatibility is about shape, not about names or ancestry.
interface Named {
name: string;
}
class Person {
constructor(public name: string, public age: number) {}
}
function greet(named: Named): string {
return `hello ${named.name}`;
}
console.log(greet(new Person("ada", 36)));
console.log(greet({ name: "grace", extra: true } as Named));
type UserId = string & { readonly brand: unique symbol };
function makeUserId(raw: string): UserId {
return raw as UserId;
}
function load(id: UserId): string {
return `loading ${id}`;
}
console.log(load(makeUserId("u-1")));
// load("u-1"); // error: a plain string is not a UserId
How it works
- Anything with the right members fits, even from another file.
- Extra members are fine, except on a fresh literal.
- A branded type is how you get nominal behavior back.
Keywords and builtins used here
NamedUserIdasclassconstructorfunctioninterfacenumberpublicreadonlyreturnstringtruetypeunique
The run, in numbers
- Lines
- 27
- Characters to type
- 570
- Tokens
- 145
- Three-star pace
- 95 tpm
At the three-star pace of 95 tokens a minute, this run takes about 92 seconds.
Step 4 of 5 in Objects & interfaces, step 14 of 23 in Types & annotations.