Skip to main content
Webpack provides excellent support for TypeScript through loaders and plugins, enabling type-safe development with full build optimization.

Basic Setup

1

Install dependencies

npm install --save-dev typescript ts-loader
2

Create tsconfig.json

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "lib": ["ES2020", "DOM"],
    "jsx": "react",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "sourceMap": true,
    "outDir": "./dist"
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}
3

Configure webpack

module.exports = {
  entry: './src/index.ts',
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: 'ts-loader',
        exclude: /node_modules/
      }
    ]
  },
  resolve: {
    extensions: ['.tsx', '.ts', '.js']
  }
};
4

Add build script

In package.json:
{
  "scripts": {
    "build": "webpack",
    "type-check": "tsc --noEmit"
  }
}
Set "module": "ESNext" in tsconfig.json to preserve ES modules for webpack’s tree shaking.

ts-loader

The standard TypeScript loader for webpack:
module.exports = {
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        loader: 'ts-loader',
        exclude: /node_modules/,
        options: {
          // Faster builds in development
          transpileOnly: true,
          // Use specific tsconfig
          configFile: 'tsconfig.build.json'
        }
      }
    ]
  }
};

transpileOnly Mode

Skip type checking for faster builds:
module.exports = {
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        loader: 'ts-loader',
        options: {
          transpileOnly: true
        }
      }
    ]
  }
};
With transpileOnly: true, type errors won’t stop the build. Run tsc --noEmit separately to check types.

Fork TS Checker Plugin

Run type checking in a separate process for faster builds:
1

Install plugin

npm install --save-dev fork-ts-checker-webpack-plugin
2

Configure webpack

const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');

module.exports = {
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        loader: 'ts-loader',
        options: {
          transpileOnly: true
        }
      }
    ]
  },
  plugins: [
    new ForkTsCheckerWebpackPlugin({
      async: true // Don't block webpack in development
    })
  ]
};
This is the recommended setup for development - it provides fast rebuilds while still showing type errors.

Babel with TypeScript

Use Babel for transpilation and TypeScript only for type checking:
1

Install dependencies

npm install --save-dev @babel/core @babel/preset-env @babel/preset-typescript babel-loader
2

Create babel.config.js

module.exports = {
  presets: [
    ['@babel/preset-env', { targets: { node: 'current' } }],
    '@babel/preset-typescript'
  ]
};
3

Configure webpack

module.exports = {
  module: {
    rules: [
      {
        test: /\.[jt]sx?$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            cacheDirectory: true
          }
        }
      }
    ]
  },
  resolve: {
    extensions: ['.tsx', '.ts', '.js', '.jsx']
  }
};
Babel is faster than ts-loader but doesn’t type check. Use with ForkTsCheckerWebpackPlugin or run tsc --noEmit separately.

Development Configuration

Optimize for fast development builds:
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');

module.exports = {
  mode: 'development',
  devtool: 'eval-source-map',
  
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        loader: 'ts-loader',
        exclude: /node_modules/,
        options: {
          transpileOnly: true // Fast builds
        }
      }
    ]
  },
  
  plugins: [
    new ForkTsCheckerWebpackPlugin({
      async: true, // Non-blocking
      typescript: {
        diagnosticOptions: {
          semantic: true,
          syntactic: true
        }
      }
    })
  ],
  
  resolve: {
    extensions: ['.tsx', '.ts', '.js']
  },
  
  cache: {
    type: 'filesystem'
  }
};

Production Configuration

Optimize for production builds:
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');

module.exports = {
  mode: 'production',
  devtool: 'source-map',
  
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        loader: 'ts-loader',
        exclude: /node_modules/,
        options: {
          transpileOnly: false // Full type checking
        }
      }
    ]
  },
  
  plugins: [
    new ForkTsCheckerWebpackPlugin({
      async: false // Block on errors
    })
  ],
  
  resolve: {
    extensions: ['.tsx', '.ts', '.js']
  }
};

Path Mapping

Use TypeScript path aliases: tsconfig.json:
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"],
      "@components/*": ["src/components/*"],
      "@utils/*": ["src/utils/*"]
    }
  }
}
webpack.config.js:
const path = require('path');

module.exports = {
  resolve: {
    alias: {
      '@': path.resolve(__dirname, 'src/'),
      '@components': path.resolve(__dirname, 'src/components/'),
      '@utils': path.resolve(__dirname, 'src/utils/')
    },
    extensions: ['.tsx', '.ts', '.js']
  }
};
Install tsconfig-paths-webpack-plugin to automatically sync webpack aliases with tsconfig paths.

React with TypeScript

npm install --save react react-dom
npm install --save-dev @types/react @types/react-dom
tsconfig.json:
{
  "compilerOptions": {
    "jsx": "react-jsx",
    "lib": ["ES2020", "DOM", "DOM.Iterable"]
  }
}
webpack.config.js:
module.exports = {
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: 'ts-loader',
        exclude: /node_modules/
      }
    ]
  },
  resolve: {
    extensions: ['.tsx', '.ts', '.js']
  }
};

Type Declarations

For Webpack Assets

Create src/types/assets.d.ts:
declare module '*.png' {
  const value: string;
  export default value;
}

declare module '*.jpg' {
  const value: string;
  export default value;
}

declare module '*.svg' {
  const value: string;
  export default value;
}

declare module '*.css' {
  const classes: { [key: string]: string };
  export default classes;
}

For Custom Modules

declare module 'my-untyped-package' {
  export function doSomething(value: string): void;
}

Environment-Specific Configs

Use different tsconfig for different environments: tsconfig.json (base):
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "strict": true
  }
}
tsconfig.build.json:
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "sourceMap": true
  },
  "include": ["src"],
  "exclude": ["**/*.test.ts"]
}
webpack.config.js:
module.exports = {
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        loader: 'ts-loader',
        options: {
          configFile: 'tsconfig.build.json'
        }
      }
    ]
  }
};

Project References

For monorepos with multiple TypeScript projects: tsconfig.base.json:
{
  "compilerOptions": {
    "composite": true,
    "declaration": true,
    "declarationMap": true
  }
}
packages/app/tsconfig.json:
{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "rootDir": "src",
    "outDir": "dist"
  },
  "references": [
    { "path": "../shared" }
  ]
}

Common Issues

Issue: Slow Builds

Solution: Use transpileOnly with ForkTsCheckerWebpackPlugin:
{
  loader: 'ts-loader',
  options: { transpileOnly: true }
}

Issue: Type Errors Not Showing

Solution: Ensure type checking is enabled:
new ForkTsCheckerWebpackPlugin({
  async: false // Block on errors in production
})

Issue: Module Resolution Errors

Solution: Check resolve extensions:
resolve: {
  extensions: ['.tsx', '.ts', '.js', '.json']
}
Always include .js in extensions array, as some dependencies may use JavaScript files.

Best Practices

1

Use transpileOnly in development

Speed up builds and use ForkTsCheckerWebpackPlugin for type checking
2

Enable strict mode

{ "compilerOptions": { "strict": true } }
3

Use ESNext modules

Preserve ES modules for better tree shaking:
{ "compilerOptions": { "module": "ESNext" } }
4

Type your webpack config

import type { Configuration } from 'webpack';

const config: Configuration = {
  // ...
};