you whish you knew before
// âś… Good (satisfies operator)
const theme = {
primary: "#ff6600",
spacing: 8,
} satisfies Record<string, string | number>;
// ❌ Bad (interface or type assertion)
interface Theme {
primary: string;
spacing: number;
}
const theme: Theme = {
primary: "#ff6600",
spacing: 8
}; // literals widened
Use satisfies
when you want to enforce a shape while
preserving literal types—perfect for tokens, settings, or config.
4.5 the-satisfies-operator
// âś… Good (string-literal union from array)
const routes = ["home", "blog", "about"] as const;
type Route = typeof routes[number];
// "home" | "blog" | "about"
// ❌ Bad (enum or plain string)
enum Route {
Home = "home",
Blog = "blog",
About = "about"
}
Use for dynamic route guards, tabs, CSS variants—any time enum is too heavy but you want strong inference.3.4 const-assertions
// âś… Good (template literal types)
type Version = "v1" | "v2";
type Resource = "users" | "posts";
type Endpoint = `/${Version}/${Resource}`;
// ❌ Bad (string concat)
const url = "/" + "v1" + "/" + "users";
type Endpoint = string;
Enforce patterns for REST routes, i18n keys, CSS naming, and more.4.1 template-literal-types
// âś… Good (unknown instead of any)
function parseJson<T>(text: string): T {
return JSON.parse(text) as unknown as T;
}
// ❌ Bad (any)
function parseJson(text: string): any {
return JSON.parse(text);
}
Use unknown
to avoid unsafe property access on
dynamic/external data.
3.0 unknown-type
// âś… Good (infer helper)
type ElementType<T> = T extends (infer U)[] ? U : never;
type Values = ElementType<[1, 2, 3]>;
// 1 | 2 | 3
// ❌ Bad (naive index type)
type ElementType<T> = T[number]; // breaks for non-array
Extract inner types from tuples, promises, responses—great for generics.2.8 conditional-types-infer
// âś… Good (asserts type guard)
function assertInput(el: HTMLElement | null):
asserts el is HTMLInputElement {
if (!(el instanceof HTMLInputElement))
throw new Error("Not an input");
}
const node = document.querySelector("#email");
assertInput(node);
node.value = "hello@example.com";
// ❌ Bad (as casting)
const node = document.querySelector("#email")
as HTMLInputElement;
node.value = "hello@example.com";
Write safer DOM or test utility code without fragile casting.3.7 assertion-functions
// âś… Good (TS 5.x const type parameters)
function defineRoutes<const R extends readonly string[]>
(routes: R) {
return routes;
}
const routes = defineRoutes(["/users", "/posts"]);
type Route = typeof routes[number];
// ❌ Bad (manual as const)
const routes = ["/users", "/posts"] as const;
Factory APIs can preserve literal types automatically—no
as const
needed.
5.0 const-type-parameters
// âś… Good (import type)
import type { User } from "./models";
//❌ Bad (standard import)
import { User } from "./models";
Reduces bundle size and speeds builds—tree-shake safely.3.8 type-only-imports-and-export
// âś… Good (exhaustive switch with never)
type Shape = { kind: "circle"; r: number } |
{ kind: "square"; s: number };
function area(shape: Shape): number {
switch (shape.kind) {
case "circle": return Math.PI * shape.r ** 2;
case "square": return shape.s ** 2;
default:
const _exhaustive: never = shape;
return _exhaustive;
}
}
// ❌ Bad (forget a case)
function area(shape: Shape): number {
if (shape.kind === "circle")
return Math.PI * shape.r ** 2;
return 0;
}
Ensure full coverage of union types—especially when adding new variants.2.0 exhaustiveness-checking
//âś… Good (project references + incremental build)
// packages/lib/tsconfig.json
{
"compilerOptions": {
"composite": true,
"outDir": "dist"
}
}
/* root tsconfig.json */
{ "files": [], "references": [{ "path": "./packages/lib" }] }
npx tsc -b # initial build
npx tsc -b --incremental # incremental
// ❌ Bad (monolithic rebuild)
npx tsc --project .
Optimize CI & local build speed in large repos or monorepos.3.0 project-references
// âś… Good (version ranges + lock files)
{
"dependencies": {
"express": "^4.18.2", // agile upgrades
"lodash": "~4.17.21", // safe patches
"react": "18.2.0" // exact pin
}
}
// ❌ Bad (loose ranges)
{
"dependencies": {
"express": "*", // any version
"lodash": ">=4.0.0" // will take major bumps
}
}
^
for devDependencies (agile upgrades)~
for prodDeps (safe patches)^
to get the latest fixes & features
automatically.
~
for production deps to limit risk to
critical patches.
^
for
faster upgrades.