TypeScript supports ES module syntax: import { ModuleName } from './module'; pulls in named exports, import * as Module from './module'; imports a whole namespace, and exports are declared with export function func() {} for named exports or export default class {} for the default export. Re-exporting from another module is as simple as export { something } from './other';. Namespaces, declared with the namespace keyword, group related code under a common name to avoid polluting the global scope. They predate ES modules and remain useful for organization, though modern code typically prefers explicit imports.
At the type level, TypeScript offers features that go well beyond simple annotations. Type guards are functions whose return type is a type predicate, like value is string, allowing the compiler to narrow the type of a value within a conditional branch. Discriminated unions extend this by giving each variant of a union a shared literal property, called a discriminant, which switch statements can exhaustively check. Conditional types resemble ternaries at the type level, mapping one type to another based on a relation—T extends null | undefined ? never : T is the pattern behind NonNullable<T>.
Mapped types iterate over the keys of another type using keyof and in to transform properties, such as { readonly [P in keyof T]: T[P] }, which is how Readonly<T> is constructed. Built on these primitives, utility types offer shortcuts for common type transformations: Partial<T> makes every property optional, Required<T> makes them all required, Pick<T, K> selects a subset of keys, and Omit<T, K> excludes them. Template literal types take this further by constructing string literal unions from interpolated expressions—for instance, `on${'click' | 'hover'}` evaluates to "onclick" | "onhover", enabling powerful compile-time string manipulation.