interface vs type| Need | Use |
|---|---|
| Object shape, might be extended/merged later | interface |
| Union, tuple, primitive alias, mapped/conditional type | type |
| Intersection composition | type (A & B) |
| Rule of thumb | default interface; reach for type only when interface can't express it |
| Need | Utility |
|---|---|
| Make every field optional | Partial<T> |
| Make every field required | Required<T> |
| Make every field readonly | Readonly<T> |
| Build a dictionary with a fixed key set | Record<K, T> |
| Keep only some fields | Pick<T, K> |
| Drop some fields | Omit<T, K> |
| Remove union members matching X | Exclude<T, X> |
| Keep only union members matching X | Extract<T, X> |
Strip null/undefined | NonNullable<T> |
| Get a function's param types | Parameters<T> |
| Get a function's return type | ReturnType<T> |
| Get a class's instance type | InstanceType<typeof C> |
| Unwrap nested Promises | Awaited<T> |
| Value shape | Technique |
|---|---|
| Union of primitives | typeof x === "..." |
| Union of class instances | x instanceof Class |
| Union of object shapes, one has a distinguishing prop | "prop" in x |
| Union of object shapes with a shared literal discriminant | check the discriminant (x.kind === "...") |
| Custom runtime check | user-defined type guard: function isX(v): v is X |
Filtering null/undefined from primitives | truthiness check (careful: also filters 0/"") or != null |
| Consumer | module | moduleResolution |
|---|---|---|
| Bundler (webpack/esbuild/Vite), tsx | esnext | bundler |
| Node.js directly, ts-node | nodenext | (implied) nodenext |
Published library via tsc | node18 | (implied) node16) |
| Bundled library | esnext | bundler (+ bundle declarations too) |
readonly / immutability quick reference| Goal | Mechanism |
|---|---|
| Block reassigning a variable | const |
| Block reassigning one property | readonly prop: T |
| Block reassigning every property of a type | Readonly<T> |
| Freeze literal types on a literal | as const |
| Block mutating array contents | readonly T[] / ReadonlyArray<T> |
| None of the above are runtime-enforced | use Object.freeze / JS #private for real enforcement |
any vs unknown vs never| Type | Accepts | Gives back |
|---|---|---|
any | everything | everything (no checking) |
unknown | everything | nothing until narrowed |
never | nothing (but itself) | everything (vacuously) |
strictFunctionTypes is on.enum gotchaskeyof EnumName ≠ what you want — use keyof typeof EnumName for key names.const enum is fully inlined — never publish one in a .d.ts for external consumers (cross-version value-mismatch risk).| Modifier | Compile-time only? | Visible from |
|---|---|---|
public (default) | — | anywhere |
protected | yes | class + subclasses (not sibling subclasses) |
private | yes (soft) | declaring class only, cross-instance OK |
#field (JS private) | no (runtime-enforced) | declaring class only |
<T extends any[]>(x: T) vs <T>(x: T[])) → degrades inferred return type.static member referencing the class's own type parameter → not allowed, only one shared static slot exists at runtime.