target and lib answer different questions
target controls JavaScript syntax retained or transformed during emit. lib selects declaration collections for checking. Adding DOM may make document known to the compiler but creates no DOM in the process. Likewise, declaring a newer API installs neither its implementation nor a polyfill.
Choose both from the supported host and delivery strategy. In the example, ES2022 identifies a language and declaration baseline; it is not a promise about every existing server. If the application uses Node-specific or browser APIs, those dependencies need appropriate types and implementations beyond the illustrated configuration.
Module configuration must represent the destination
module and moduleResolution participate in the module model and import resolution. The example assumes nodenext and a package.json containing type: module. verbatimModuleSyntax makes the distinction explicit between erased type imports and value imports retained in this ESM context.
If files are interpreted as CommonJS, this mode does not silently convert ESM syntax into require calls. A diagnostic should lead to reviewing format and configuration rather than disabling options until it disappears. Configuration accepting the files is useful only if it represents the environment consuming the artifacts.
Checking and emitting can be distinct stages
noEmit allows using the compiler for checking without producing its output files. It is useful when another tool generates JavaScript, but does not guarantee that tool checks types. The pipeline must require checking results before accepting the transformed artifact from the same revision.
noEmitOnError has another purpose: preventing new emission when compilation contains errors. The option does not delete results from earlier runs. Finding dist after failure does not establish that the current revision produced acceptable content. Identify artifact origin and use isolated outputs or controlled cleanup to avoid confusing runs.
Migrate JavaScript without overstating coverage
allowJs permits including JavaScript files in a TypeScript project, supporting gradual transition. checkJs adds diagnostics to included JavaScript files. Inclusion and checking are related but distinct decisions; a team should record which files and configurations belong to each stage.
Start with useful boundaries such as exported functions and received data, preserving required behavior while improving type information. Adding any to every call may reduce diagnostics without increasing confidence. Migration should identify areas still poorly described and avoid treating the .ts extension as sufficient evidence of quality.
The scope of skipLibCheck should remain visible
skipLibCheck omits checking declaration files. It can reduce checking work or temporarily bypass conflicts, but reconciles neither incompatible versions nor delivered implementations. Uses of types in application code still participate in analysis.
When the option is used because of duplicate declarations, record the cause and resolution decision. Repairing the dependency tree or aligning versions may remove the inconsistency being hidden. Do not conclude that a package contract is correct merely because part of its declarations is no longer being checked.
CLI and API are distinct integration surfaces
This lesson uses the TypeScript 7.0 baseline. Its release distinguishes the native CLI from the programmatic API: 7.0 does not supply that API. A tool importing the earlier API has not migrated merely because the native checking command works. Each tool’s dependency needs separate analysis.
Documentation describes @typescript/typescript6 and npm aliases for coexistence with the 7.0 CLI when a tool still needs the 6.0 API. Use explicit versions and a mechanism compatible with the consumer. Coexistence can be a valid operational decision, but should retain the pending migration record; an intention about a future version does not establish availability in 7.0.
Guided reading of a publication decision
In the shown configuration, src bounds source and dist receives output. strict and noUncheckedIndexedAccess increase diagnostics in areas studied earlier. noEmitOnError prevents new emission with errors, but a publication decision still needs the current run’s result, analyzed revision and corresponding artifact.
Compare two records: one contains only “dist exists”; the other identifies revision, compiler version, configuration, checking result and content to publish. The second supports investigating differences. Pinning dependencies and a supported host also avoids attributing to code differences caused by a silent tool change or target: ESNext.
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022"],
"module": "nodenext",
"moduleResolution": "nodenext",
"strict": true,
"noUncheckedIndexedAccess": true,
"verbatimModuleSyntax": true,
"noEmitOnError": true,
"rootDir": "src",
"outDir": "dist"
},
"include": ["src/**/*.ts"]
}Illustrative TypeScript 7.0 configuration for a package with type: module, code under src and an ES2022-compatible host. It supplies neither DOM APIs nor Node-specific declarations. Failure does not clean dist; publication depends on the current result and artifact identity.
Common pitfalls
Treating lib as a polyfill; ignoring failed tsc because dist contains files; enabling skipLibCheck as a dependency repair; confusing CLI compatibility with API compatibility.
Related topics: Static types and runtime values · External data and error boundaries · Modules, declarations and host contracts
Accept delivery through the relationship between revision, checks and identified artifact. Explicit configuration lets teams discuss limits and repeat decisions.
Reference: TypeScript: target · TypeScript 7.0; explicit strict and host configuration