syt
v0.2.0
Published
A fluent, type-safe builder for tsconfig.json files, with zod validation.
Maintainers
Readme
syt
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.
Installation
npm install sytQuick start
import { 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')Loading and editing an existing tsconfig
const config = TsConfigBuilder.fromFile('./tsconfig.json')
.addAlias('#imports', ['./.nuxt/imports.d.ts'])
.setLib(['ESNext', 'DOM'])
.write('./tsconfig.json')Merging configs
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.
API
Constructing
| 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. |
extends
| Method | Description |
| --- | --- |
| .setExtends(path) | Sets or replaces the extends field. |
compilerOptions — generic
| 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. |
compilerOptions — convenience booleans
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.
compilerOptions — convenience enums / values
| 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.
Paths / aliases
| 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. |
include / exclude / files
.addInclude(pattern), .removeInclude(pattern), .addExclude(pattern), .removeExclude(pattern), .addFile(path), .removeFile(path) — all accept a single string or an array.
references
.addReference(path), .removeReference(path) — for TypeScript project references.
Merging
| Method | Description |
| --- | --- |
| .merge(other, opts?) | Merges another config into this one (chainable). |
| TsConfigBuilder.merge(base, other, opts?) | Static/immutable variant — returns a new builder. |
Output
| 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. |
Type safety
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 allowedLicense
MIT
