A fluent, type-safe builder for tsconfig.json files — with zod validation built in.
Create, edit, merge, and write tsconfig.json files programmatically, with autocomplete and compile-time type checking on the compiler options you actually use.
npm install sytimport { TsConfigBuilder } from 'syt'
const config = new TsConfigBuilder()
.setTarget('ES2022')
.setModule('ESNext')
.setModuleResolution('Bundler')
.strict()
.composite()
.skipLibCheck()
.addAlias('~/*', ['./src/*'])
.addInclude('src/**/*.ts')
.addExclude('node_modules')
.write('./tsconfig.json')const config = TsConfigBuilder.fromFile('./tsconfig.json')
.addAlias('#imports', ['./.nuxt/imports.d.ts'])
.setLib(['ESNext', 'DOM'])
.write('./tsconfig.json')const merged = TsConfigBuilder.merge(
TsConfigBuilder.fromFile('./tsconfig.base.json'),
{ compilerOptions: { paths: { '~/*': ['./src/*'] } } },
)
merged.validate() // throws if the result isn't a valid tsconfig
merged.write('./tsconfig.json')By default, merge lets the second config win on scalar compilerOptions conflicts, while paths, include, exclude, files, and references are unioned (deduplicated). Pass { strategy: 'self-wins' } to flip the conflict behavior for scalar options.
| Method | Description |
|---|---|
new TsConfigBuilder(initial?) |
Creates a builder, optionally from an existing config object. Validates via zod. |
TsConfigBuilder.fromFile(path) |
Loads a tsconfig.json from disk. |
TsConfigBuilder.validate(data) |
Static: validates an arbitrary object against the schema. |
.validate() |
Validates the builder's current config. Throws if invalid. |
| Method | Description |
|---|---|
.setExtends(path) |
Sets or replaces the extends field. |
| Method | Description |
|---|---|
.setCompilerOption(key, value) |
Sets any option. Type-checked for known keys, unknown for the rest. |
.getCompilerOption(key) |
Reads an option, typed for known keys. |
.removeCompilerOption(key) |
Removes an option. |
Each accepts an optional boolean (default true), so both enabling and disabling are one-liners:
builder.strict().sourceMap(false)strict, strictNullChecks, composite, incremental, declaration, declarationMap, sourceMap, skipLibCheck, esModuleInterop, allowSyntheticDefaultImports, isolatedModules, resolveJsonModule, allowJs, checkJs, noEmit, noImplicitAny, noUnusedLocals, noUnusedParameters, forceConsistentCasingInFileNames, verbatimModuleSyntax, useDefineForClassFields, experimentalDecorators, emitDecoratorMetadata.
| Method | Description |
|---|---|
.setTarget(target) |
e.g. 'ES2022', 'ESNext' |
.setModule(module) |
e.g. 'ESNext', 'NodeNext' |
.setModuleResolution(resolution) |
e.g. 'Bundler', 'NodeNext' |
.setJsx(jsx) |
e.g. 'react-jsx' |
.setModuleDetection(mode) |
'auto' | 'legacy' | 'force' |
.setOutDir(dir) / .setRootDir(dir) / .setBaseUrl(url) |
Path options |
.setLib(libs) / .addLib(lib) |
Replace or extend lib |
.setTypes(types) / .addType(type) |
Replace or extend types |
Enum values are validated case-insensitively (tsc itself accepts "esnext" and "ESNext" alike) without rewriting your casing.
| Method | Description |
|---|---|
.addAlias(alias, paths) |
Adds/merges an alias in compilerOptions.paths. |
.removeAlias(alias) |
Removes an alias. |
.setAliases(paths) |
Replaces the whole alias map. |
.hasAlias(alias) |
Checks whether an alias exists. |
.addInclude(pattern), .removeInclude(pattern), .addExclude(pattern), .removeExclude(pattern), .addFile(path), .removeFile(path) — all accept a single string or an array.
.addReference(path), .removeReference(path) — for TypeScript project references.
| Method | Description |
|---|---|
.merge(other, opts?) |
Merges another config into this one (chainable). |
TsConfigBuilder.merge(base, other, opts?) |
Static/immutable variant — returns a new builder. |
| Method | Description |
|---|---|
.toObject() |
Returns a plain object copy of the config. |
.toJSON(indent?) |
Serializes the config as a JSON string. |
.write(path, indent?) |
Writes the config to disk, creating parent directories as needed. |
Known compilerOptions keys are checked at compile time:
builder.setCompilerOption('composite', true) // ✅
builder.setCompilerOption('composite', 'yes') // ❌ TS error: string not assignable to boolean
builder.setCompilerOption('target', 'ES2022') // ✅ with autocomplete
builder.setCompilerOption('myCustomOption', 42) // ✅ unlisted keys are still allowedMIT