TypeScript Tutorial
TypeScript Interfaces
interface names a contract. Classes implement it. Objects can satisfy it without a class.
A named contract
An interface lists the fields and methods a value must have. It is a type. It is not a constructor. You cannot new an interface. You write objects that match it, or classes thatimplements it.
C++ abstract classes often play this role with pure virtual functions. TypeScript splits the idea: useinterface for the contract, and an abstract class only when you also need a constructor or a method body to inherit. Structural typing means any object with the right shape already qualifies, even if it never mentioned the interface name.
An object can satisfy an interface
Declare the interface. Then annotate a variable with that name. The object literal must include every required field. Extra fields on a fresh literal are an error. Missing fields are an error.
Example
interface Point {
x: number;
y: number;
}
const p: Point = { x: 3, y: 4 };
console.log(p.x + "," + p.y);
function show(pt: Point): void {
console.log("(" + pt.x + ", " + pt.y + ")");
}
show(p);
show({ x: 0, y: 1 });Output is 3,4 then (3, 4) then (0, 1). There is no class. The functionshow only cares that the argument has x and y as numbers.
Compile this at /typescript/try. Drop y from the literal and tsc reports that Point is missing a property.
A class implements the contract
Write implements Point (or several interfaces, separated by commas). tsc checks that the class actually has those members. Callers can still type a parameter as Point and pass the instance.
Example
interface Named {
name: string;
}
class Player implements Named {
constructor(public name: string, public score: number) {}
}
function greet(n: Named): void {
console.log("hello " + n.name);
}
const p = new Player("Ada", 12);
greet(p);
greet({ name: "Kai" });Output is hello Ada then hello Kai. Player has extra state (score). greet only needs name. The second call is a plain object, not a class. Both satisfy Named.
Methods on an interface
An interface can list functions. A class that implements it must provide those methods. An object literal can provide them as well, as function properties.
Example
interface Drawable {
kind(): string;
}
class Circle implements Drawable {
kind(): string {
return "circle";
}
}
class Square implements Drawable {
kind(): string {
return "square";
}
}
function show(d: Drawable): void {
console.log(d.kind());
}
show(new Circle());
show(new Square());
show({ kind: () => "dot" });Output is circle, square, then dot. The last argument is not a class. It still implements the contract by having a kind function that returns a string.
interface versus type versus abstract class
| Tool | Use it when |
|---|---|
interface | You want a named object or method contract, and implements. |
type alias | Unions, tuples, or a one-off object shape (type aliases chapter). |
abstract class | You also need a constructor or a method body to inherit. |
Two interfaces with the same fields are compatible. That is structural typing: the shape matters, not the declared name, when you pass a value. implements is still useful as a check that a class did not forget a method.
Optional members
A trailing ? on a field means callers may omit it. Narrow or use ?? before you depend on it, the same as strict null.
Example
interface Player {
name: string;
team?: string;
}
function city(p: Player): string {
return p.team ?? "none";
}
console.log(city({ name: "Ada", team: "London" }));
console.log(city({ name: "Kai" }));Output is London then none.
End of this stretch
This is the last chapter in the TypeScript lesson list. Return to /typescript for the full menu, or to /typescript/examples for complete programs you can copy. Anything that still feels new compiles at /typescript/try.
Open the Drawable listing with Try it in TypeScript. Add a third class that implements kind(), pass it to show, and run again. The function does not change.