The project
Run tsc with no file names and it looks for tsconfig.json, first in the current folder, then in each parent folder. That file marks a project: every compiler setting in one place, so everyone builds the same way.
"include": ["src"] says which files belong to the project: every TypeScript file in the src folder. Here that is src/index.ts. tsc reads them all together, so one file can use another's types.
How strict
"strict": true switches on a whole family of stricter checks at once. One of them, noImplicitAny, refuses to let tsc quietly guess the type any, which would switch checking off for that value.
tsc checks src/index.ts. On line 1, n has no type, so it would be any. Because strict is on, tsc reports error TS7006: Parameter 'n' implicitly has an 'any' type. With "strict": false, the same file passes.
Write the type: n?: string. The ? means hi can be called without n, so n is a string or undefined. Run tsc again: every value has a known type, 0 errors.
Which JavaScript
"target": "es2019" says which version of JavaScript to write. The ?? operator on line 2 only arrived in ES2020, so for es2019 tsc must rewrite it using older JavaScript.
"outDir": "dist" sends the output to dist/index.js. The types are gone and ?? became a longer test for null and undefined. tsc also starts the file with "use strict";.
Change target to "es2020" and run tsc again. ES2020 has ??, so line 3 keeps it as you wrote it. Same source, different JavaScript: tsconfig.json decides.
What happens
;; step 1/8 · project
$ tsc
looks for tsconfig.json here, then in each parent folder
tsconfig.json
1 { "compilerOptions": {
2 "target": "es2019",
3 "strict": true,
4 "rootDir": "src",
5 "outDir": "dist" },
6 "include": ["src"] }
with file names (tsc a.ts) tsc does not use it:
it stops with error TS5112 unless you add --ignoreConfig
Every error and every dist/index.js shown is exactly what tsc 7.0.2 writes for these files (tsc 6.0.3 writes the same). Defaults change between major versions, so set the options you rely on instead of trusting the defaults. "rootDir": "src" tells tsc where the source starts, so src/index.ts becomes dist/index.js. Since TypeScript 6.0, leaving it out here is error TS5011. tsc writes "use strict"; at the top of a script file (one with no import or export). Since TypeScript 6.0 it does so with or without "strict". By default tsc still writes the .js files when it finds type errors; set "noEmitOnError": true to stop that.