TypeScript Survival Guide

Favorite typescript videos

104 — Type vs Interface: the Handbook Is Backwards (default to type)

Full companion narrative for I Cannot Believe TypeScript Recommends You Do This — Kyle's case for defaulting to type aliases and reaching for interface only for declaration merging

Video: 104 · I Cannot Believe TypeScript Recommends You Do This! · watch · ~07:44 · Web Dev Simplified (Kyle)

Source: this is a written companion to the video. Part of the Favorite TypeScript Videos curated path, module 02 (type system) — the sequel to 103: where that lesson’s filter(Boolean) and JSON.parse fixes are expressed as type aliases, this one argues that should be the default everywhere. Prerequisite for 105, whose predicates can only narrow union types.

the one idea: default to type, not interface

Kyle opens on a split screen — a type UserType and an interface UserInterface side by side — and states his thesis up front: the TypeScript handbook recommends interfaces by default, and he thinks that recommendation is wrong. He rewrites each snippet live in present tense over the editor so the viewer watches the compiler react.

Kyle: “in my opinion, this is completely backwards because interfaces are more complicated than types, they have less features than types.”

type alias and interface side by side in the opening editor

declaration syntax: = versus a block

Both shapes consume identically at use sites — the difference lives entirely in the declaration. A type alias binds a name with =, which is why it can name anything; an interface only accepts an object-shaped block.

type UserType = { name: string; age: number };
interface UserInterface {
	name: string;
	age: number;
}

const a: UserType = { name: "Kyle", age: 30 };
const b: UserInterface = { name: "Kyle", age: 30 };

interface definition taking shape in scripts.ts

non-object types are types-only

An interface cannot name a primitive alias. Kyle tries interface SInter = string on screen and shows it is physically impossible — no =, no non-object right-hand side. Anything that is not an object literal shape forces a type, which is the first way an interface-first codebase ends up mixing both constructs anyway.

type SType = string;
const greeting: SType = "hello";

type StringOrNumber = string | number;
const id: StringOrNumber = 123;

type alias naming a primitive in type.ts

unions need types

Kyle builds a union of two object shapes and shows there is no interface spelling of “or”. Defining the two member interfaces is possible, but combining them with | still requires a type alias, so union-heavy domain modeling always routes through type.

type Name = { name: string };
type Age = { age: number };
type NameOrAge = Name | Age;

const v: NameOrAge = { age: 42 };

intersection: & versus extends

Both constructs can combine shapes, and Kyle demonstrates each: & for types, extends for interfaces. The interface form has a sharp edge he hits live — the parent must already be a named type or interface, so inline extension fails until he breaks the parent out into its own declaration.

type Named = { name: string };
type NamedAndAged = Named & { age: number };

interface N {
	name: string;
}
interface Person extends N {
	age: number;
}

combined member shapes resolving in the editor

the speed argument is stale

Kyle addresses the claim that interfaces compile faster: it may have been true years ago, but on modern TypeScript the build-time difference is negligible. He rules speed out as a decision criterion — pick on expressiveness, not folklore. Settle it on your own repo instead of restructuring declarations:

npx tsc --noEmit --extendedDiagnostics | grep -E "Total time|Types:"

declaration merging is the one interface-only feature

The single capability types lack: repeat an interface name and the declarations merge. Kyle shows the legitimate use — extending the global Window with a custom property — then warns that the same behavior inside your own codebase is usually an accidental-merge footgun, where a typo’d duplicate silently widens a type instead of erroring like a duplicate type would.

interface Window {
	test: string;
}
window.test = "hello";
window.test = 42;

interface User {
	name: string;
}
interface User {
	age: number;
}

duplicate User interface merging silently in the editor

merged User shape confirmed against the duplicate type error

Prev: 103 — Did He Really Fix TypeScript? · Next: 105 — Type Predicates Fix the Extracted-Guard Bug

Watch right after 103: that lesson warns that any leaks in through built-in signatures, and every fix it demonstrates is a type alias — this video makes that the house rule. Pairs forward with 105: predicates narrow union types, and unions are types-only per the sections above, so this video is the prerequisite. Pays off at project scale in 107, where every props object and the sidebar context value are type aliases.

Whisper mistranscriptions corrected for type vs interface. Frame timestamps run ~01:27 (split-screen opener) through ~06:17 (merge demo); the opening frame is blank and the closing frame is talking-head, so screenshots sample frames 2–7.