Tags: typescript, javascript, types, typing, compilation, generics
Level: intermediate
TL;DR: Static typing superset for JavaScript providing compile-time type safety, structural typing, and zero runtime overhead.
Compiles down to standard JavaScript removing all types at build time.
Operates on structural typing where type compatibility depends on shape, not name.
Type inference automatically deduces types when explicit annotations are omitted.
any disables type checking completely, whereas unknown forces type checking before usage.
Union types define values that can be one of several types.
Intersection types combine multiple types into a single unified contract.
Generics allow reusable, type-safe components parameterized by type variables.
Discriminated unions use a common literal property to narrow variant types safely.
Mapped types transform existing types into new shapes programmatically.
Narrowing refines broad types into specific types via type guards.
Q: What is the difference between interface and type in TypeScript?R: I use interface for open object contracts that benefit from declaration merging, and type for unions, primitives, tuples, and complex type transformations.
Q: How does structural typing differ from nominal typing?R: In TypeScript, two types are compatible if they share the same structure and members, regardless of their declared class or interface names.
Q: Why prefer unknown over any when handling untrusted data?R: unknown prevents accidental operations until I explicitly narrow the type using guards, while any completely disables the compiler's safety checks.
Q: How do discriminated unions help in complex business logic?R: By defining a common literal tag on each variant, the compiler ensures exhaustiveness in switch statements and safely narrows each branch automatically.
Using non-null assertion ! without verifying runtime presence can throw null pointer errors.
Excessive use of any propagates untyped values throughout the codebase.
Confusing type casting as TargetType with runtime data conversion or validation.
Relying on keyof over object instances without handling index signatures properly.
Assuming TypeScript interfaces and types exist or perform validations during runtime.
// Discriminated union with exhaustive check
type SuccessResponse = { status: "success"; data: string };
type ErrorResponse = { status: "error"; message: string };
type ApiResponse = SuccessResponse | ErrorResponse;
function handleResponse(res: ApiResponse): string {
switch (res.status) {
case "success":
return res.data;
case "error":
return res.message;
default: {
const _exhaustiveCheck: never = res;
throw new Error(`Unhandled case: ${_exhaustiveCheck}`);
}
}
}
TypeScript
// Custom type guard
function isString(val: unknown): val is string {
return typeof val === "string";
}
Bash
# Type check without emitting JavaScript files
npx tsc --noEmit
[ ] Conditional types and the infer keyword
[ ] Utility types: Partial, Required, Readonly, Record, Pick, Omit
[ ] Declaration files (.d.ts) and ambient declarations
[ ] Template literal types
[x] Basic types and interface declarations
[x] Generics basics and constraints
TypeScript Official Documentation: Handbook
TypeScript Compiler Options Reference (tsconfig.json)