Skip to content

interface

interface Name: declares a structural contract. Lowered to class Name(Protocol): from typing.

interface Drawable:
def draw(self) -> None
def width(self) -> float
def height(self) -> float

Members

An interface may declare:

  • Method signatures: def name(self, ...) -> R (no body — ... is implicit).
  • Field signatures: name: T.
interface Stored:
id: int
def serialise(self) -> dict[str, str]

Structural conformance

A class satisfies an interface if it provides every required member with compatible signatures. No implements clause:

class Button:
label: str
impl Button:
def draw(self) -> None: ...
def width(self) -> float: return 10.0
def height(self) -> float: return 1.0
def render(d: Drawable) -> None: ...
render(Button(label="x")) # ✅ structurally matches

The checker verifies at the call / assignment site.

isinstance is rejected by default

isinstance(x, Drawable) # ❌ tyc::interface_isinstance

Use static narrowing or refactor to a sealed union. See Interfaces (Protocols) for the full reasoning.

Generic interfaces

interface Container[T]:
def add(self, item: T) -> None
def items(self) -> list[T]

Bound at the use site:

def consume[T](c: Container[T]) -> int:
return len(c.items())

Bounded type parameters

Interfaces are valid as bounds for generic type parameters:

def smallest[T: Ordered](xs: list[T]) -> T?: ...

(Bounded inference is partial in v1; verify with tyc check.)

Emit

interface Drawable:
def draw(self) -> None

Where next