Hey there! π After spending countless hours banging my head against TypeScript configs (and making every mistake possible), I thought I’d write down everything I’ve learned to help other devs avoid the same headaches. Let’s dive in!

Getting Started with TypeScript Config – A No-BS Guide
Overview
Before we jump into the nitty-gritty, let me tell you why TypeScript configuration matters. When I first started with TS, I just copy-pasted configs from Stack Overflow (we’ve all been there, right?). But understanding your tsconfig is like having a good set of tools – it makes everything easier.
Quick tip: You can create a tsconfig.json by running:
npx tsc --init
This gives you a config file with tons of commented options. Pretty neat, huh?
Introduction
TypeScript configuration is a crucial aspect of any TypeScript project that determines how your code is compiled, type-checked, and integrated with your development environment. The cornerstone of this configuration is the tsconfig.json file, which serves as the command center for TypeScript’s compiler options and project settings.
TSConfig Structure
The tsconfig.json file isn’t as scary as it looks. Think of it like a recipe – you’ve got your main ingredients (root options) and your spices (compiler options). Here’s what a basic one looks like:
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"outDir": "./dist"
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
Understanding TSConfig Files
Project Root Identification
The presence of a tsconfig.json file in a directory indicates that it’s the root of a TypeScript project. This file is essential for:
- Defining the project boundaries
- Specifying compilation settings
- Managing type checking behavior
- Configuring module resolution
- Setting output preferences
- Core Structure
Core Structure
The TypeScript configuration file follows a specific structure with two main sections: root-level and the compilerOptions section. It provides flexibility through comments and inheritance, making it easy to customize and maintain. Modern IDEs, such as Visual Studio Code and WebStorm, support these features without treating comments as syntax errors. Additionally, it allows modular configurations by enabling the division of options across multiple files, which can then be merged using the extends directive.
- Root-Level Options: These include
extends,files,include, andexclude. Other options, likereferencesandtypeAcquisition, complement the compiler settings. - Compiler options (
compilerOptions): This section is dedicated to defining how the TypeScript compiler should process your code.
{
"extends": "./base-config.json",
"files": [...],
"include": [...],
"exclude": [...],
"compilerOptions": {
// Compiler-specific settings
}
}
Root Section Configuration
1. Extends
Type: string | false
Default: false
The extends option enables configuration inheritance, allowing you to:
- Create base configurations that can be shared across projects
- Override specific options while maintaining a common foundation
- Organize configurations by environment (development, production, testing)
Example of configuration inheritance:
// base-tsconfig.json
{
"compilerOptions": {
"target": "ES6",
"strict": true
}
}
// tsconfig.development.json
{
"extends": "./base-tsconfig.json",
"compilerOptions": {
"sourceMap": true,
"watch": true,
"noUnusedLocals": false
}
}
2. Files
Type: string[] | false
Default: false
The files option explicitly lists specific files to include in compilation:
- Useful for small projects with a limited number of files
- Takes precedence over
includeandexclude - Must specify the full path relative to the config file
Example:
{
"files": [
"src/core/main.ts",
"src/types/global.d.ts",
"src/entry.ts"
]
}
3. Include
Type: string[]
Default: ["**/*"] (if files is not specified)
The include option uses glob patterns to specify which files to include:
- Supports wildcards (
*,**) - Can target specific file extensions (
.ts,.tsx,.d.ts) - Works in conjunction with
exclude
Common patterns:
{
"include": [
"src/**/*", // All files in src directory
"tests/**/*.spec.ts", // All test files
"types/**/*.d.ts" // All type definition files
]
}
4. Exclude
Type: string[]
Default: ["node_modules", "bower_components", "jspm_packages"]
The exclude option specifies files to ignore during compilation:
- Always excludes
node_modulesby default - Cannot override files specified in
files - Doesn’t prevent file inclusion through imports
Advanced exclude configuration:
{
"exclude": [
"node_modules",
"**/*.test.ts",
"**/*.spec.ts",
"dist",
"build",
"temp"
]
}
Compiler Options Deep Dive
1. Target
Type: string
Default: "ES3"
The target option specifies the ECMAScript target version:
{
"compilerOptions": {
"target": "ES2020",
"lib": ["ES2020", "DOM"],
"module": "ESNext"
}
}
Supported values:
ES3(legacy)ES5(broad browser support)ES6/ES2015ES2016throughES2022ESNext(latest supported)
2. Module
Type: string
Default: Based on target
Module system configuration:
{
"compilerOptions": {
"module": "CommonJS",
"moduleResolution": "node",
"esModuleInterop": true
}
}
Common options:
CommonJS(Node.js)ESNext(Modern browsers)UMD(Universal)AMD(Legacy browsers)System(SystemJS)
3. Strict Mode (aka The Pain Train)
TypeScript’s strict mode includes several granular settings:
{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"noImplicitThis": true,
"useUnknownInCatchVariables": true
}
}
4. Module Resolution
Type: string
Default: Based on module
Controls how TypeScript resolves module imports:
{
"compilerOptions": {
"moduleResolution": "node",
"baseUrl": "./src",
"paths": {
"@/*": ["*"],
"@components/*": ["components/*"]
}
}
}
5. Output Configuration
Controls the compilation output:
{
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src",
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"removeComments": true
}
}
Advanced Features
1. Path Aliases
Configure import path aliases for cleaner imports:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@app/*": ["src/app/*"],
"@core/*": ["src/core/*"],
"@shared/*": ["src/shared/*"],
"@environments/*": ["src/environments/*"]
}
}
}
2. Type Acquisition
Control automatic type definition acquisition:
{
"typeAcquisition": {
"enable": true,
"include": ["jquery"],
"exclude": ["node"]
}
}
3. Project References
Configure project dependencies for monorepos:
{
"references": [
{ "path": "../core" },
{ "path": "../common" }
],
"compilerOptions": {
"composite": true
}
}
Environment-Specific Configurations
Development Configuration
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"sourceMap": true,
"declarationMap": true,
"watch": true,
"preserveWatchOutput": true,
"noUnusedLocals": false,
"noUnusedParameters": false
}
}
Production Configuration
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"sourceMap": false,
"removeComments": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"importsNotUsedAsValues": "error"
}
}
Best Practices
1. Inheritance Over Duplication
- Use
extendsto share common configurations - Override only what’s necessary for specific environments
2. Progressive Type Checking
- Start with basic type checking
- Gradually enable strict mode options
- Add stricter checks as the project matures
3. Module Resolution
- Use
"moduleResolution": "node"for modern projects - Configure path aliases for clean imports
- Maintain consistent import styles
4. Output Management
- Use clear output directory structure
- Enable source maps for development
- Generate declaration files for libraries
5. Performance Optimization
- Limit the scope of
include - Use specific
excludepatterns - Leverage project references for large codebases
Difference Between TSConfig.json and jsConfig.json
This one tripped me up for a while! Here’s the deal:
- tsconfig.json: For TypeScript projects
- jsconfig.json: For JavaScript projects that want some TypeScript features
The jsconfig.json is basically a tsconfig.json with allowJs: true by default. Use tsconfig for TS projects, jsconfig for JS projects with TS features.
Tips from My Mistakes
- Don’t turn off strict mode! I did this when starting out and regretted it.
- Keep your include/exclude patterns simple
- Use path aliases from the start – trust me, you’ll thank me later
- Don’t copy-paste configs without understanding them (learned this one the hard way)
- Start with a base config and customize as needed
Conclusion
Whew, that was a lot! But honestly, once you get the hang of TypeScript configuration, it becomes second nature. Start simple, gradually add more options as you need them, and don’t be afraid to experiment.
A well-configured TypeScript project is essential for maintaining code quality and developer productivity. Key takeaways:
- Understanding the configuration structure enables better project organization
- Proper file inclusion/exclusion patterns prevent unnecessary compilation
- Environment-specific configurations optimize development workflow
- Strict type checking improves code quality
- Path aliases and module resolution enhance code organization
Remember to regularly review and update your TypeScript configuration as your project evolves and new TypeScript features become available. TypeScript is here to help, not to make your life harder. A good config setup will catch bugs early and make your code more maintainable.
Got questions? Feel free to reach out! I’m always happy to help fellow devs figure this stuff out.
Happy coding! π
P.S.: If you found this guide helpful, maybe buy me a coffee? Just kidding, but do share it with other devs who might need it!