Duck typing

2 snippets across 2 stacks — Python, TypeScript

PYPython

Protocols (Structural Typing)

PY · Classes & OOP
syntax
from typing import Protocol
class Drawable(Protocol):
    def draw(self) -> None: ...
example
from typing import Protocol

class Saveable(Protocol):
    def save(self, path: str) -> None: ...

class Document:
    def save(self, path: str) -> None:
        print(f"Saved to {path}")

def backup(item: Saveable, dest: str) -> None:
    item.save(dest)

backup(Document(), "/tmp/doc.txt")
output
Saved to /tmp/doc.txt

Note Protocols enable duck-typing with static type checking. Classes do not need to explicitly inherit from the Protocol; they just need matching methods.

TSTypeScript

Structural Typing Surprises

TS · Common Mistakes
syntax
// TypeScript uses structural (shape) typing, not nominal (name) typing
example
interface Cat {
  name: string;
  purr(): void;
}

interface Robot {
  name: string;
  purr(): void;
}

// These are the SAME type to TypeScript!
const robot: Robot = { name: "RoboCat", purr() { console.log("bzzz"); } };
const cat: Cat = robot; // No error — shapes match

// Excess property checking only works on object literals:
const direct: Cat = {
  name: "Whiskers",
  purr() {},
  // batteries: true, // Error: Object literal may only specify known properties
};

// But NOT on variables:
const obj = { name: "X", purr() {}, batteries: true };
const sneaky: Cat = obj; // No error — extra properties allowed from variables
output
// Two types with the same shape are interchangeable, regardless of name

Note Structural typing means TypeScript cares about shape, not name. Excess property checking only catches extra properties on direct object literals — not on variables. This often surprises developers from C#/Java backgrounds. Use branded types if you need nominal distinction.