paths maps an import specifier to a location for the type checker. Patterns have at most one *; the longest matching prefix wins; each key may list fallbacks. It does not change the emitted import. A @lib/util.js import is written to the output exactly as typed, so the runtime or bundler must resolve the alias itself (via bundler config, or Node's package.json "imports", which the TypeScript docs recommend as the standard replacement). Libraries should not use paths aliases: consumers cannot resolve them. Do not point paths at node_modules or monorepo packages; resolution then skips exports and main. Use workspaces symlinks.
baseUrl (from the AMD era) made bare specifiers resolve from a directory, and paths values were relative to it. Since TS 4.1 paths needs no baseUrl and resolves relative to the config file. TS 6.0 deprecated baseUrl (TS5101) and TS 7.0 removed it (TS5102): fold its directory into each paths value.
extends loads a base config first, then applies the child over it. Relative paths in a config resolve against the file that wrote them. Since TS 5.0 it accepts an array; later entries win. references is the one top-level key not inherited.
What gets compiled: files is an exact list (a missing file is an error); include is a glob list (default **/* when files is absent); exclude only filters what include found. A file excluded this way still compiles if something imports it, references it, or lists it in files. files, include and exclude in the child replace the base's, they are not merged.