DevToolBoxฟรี
บล็อก

TypeScript to JavaScript: The Complete Conversion Guide (5 Methods)

14 min readโดย DevToolBox

TL;DR

Converting TypeScript to JavaScript means stripping type annotations, interfaces, enums, and other TS-only syntax to produce valid JS. You can use the official tsc compiler, our free online converter, Babel with @babel/preset-typescript, esbuild (the fastest option), or SWC (Rust-based speed). This guide covers every method, common pitfalls with enums and decorators, how to preserve JSDoc for IDE support, and integration with Vite, webpack, and Rollup build pipelines.

Key Takeaways

  • The TypeScript compiler (tsc) is the most accurate way to convert TypeScript to JavaScript but is also the slowest for large codebases.
  • esbuild and SWC perform type-stripping only (no type checking) and are 10-100x faster than tsc.
  • Babel with @babel/preset-typescript strips types while keeping your existing Babel plugin pipeline intact.
  • TypeScript enums, namespaces, and const enum require special handling because they emit runtime JavaScript code.
  • Decorators (experimental or TC39 Stage 3) need transpilation, not just type stripping.
  • Converting JSDoc comments preserves IDE IntelliSense in the output JavaScript files.
  • Our TypeScript to JavaScript converter handles all these edge cases in a single click.

Why Convert TypeScript to JavaScript?

TypeScript has become the default language for modern web development, with adoption growing rapidly year over year. But there are many practical scenarios where you need to convert TypeScript back to plain JavaScript. Understanding when and why this conversion is necessary helps you choose the right tool and approach.

Publishing npm packages: Most npm packages ship compiled JavaScript alongside type declaration files (.d.ts). This ensures compatibility with consumers who do not use TypeScript. The tsc compiler generates both the JavaScript output and the declaration files in a single pass.

Running in browsers: No browser natively executes TypeScript. Whether you use a bundler like Vite or webpack, the TypeScript code must be transformed to JavaScript before it reaches the browser. Understanding this compilation step helps you debug source map issues and optimize build times.

Migrating away from TypeScript: Some teams decide to remove TypeScript from their stack. This might happen when a project is being handed to a team less familiar with TypeScript, or when the type maintenance overhead exceeds the benefits for a small project. In such cases, a bulk TS-to-JS conversion is needed.

Learning and prototyping: Developers learning JavaScript sometimes encounter TypeScript examples online and need to understand the equivalent JavaScript. An online TS to JS converter makes this translation instant.

Legacy system integration: Older build systems, serverless platforms, or embedded environments may only support vanilla JavaScript. Converting TypeScript output to a specific ES version (ES5, ES2015, ES2020) ensures compatibility with these constrained runtimes.

Method 1: Using the TypeScript Compiler (tsc)

The official TypeScript compiler is the most reliable way to convert TS to JS. It performs full type checking, handles all TypeScript syntax including enums and namespaces, and produces accurate JavaScript output. Here is how to set it up:

Installation

# Install TypeScript globally
npm install -g typescript

# Or install locally in your project
npm install --save-dev typescript

# Verify installation
tsc --version

Basic Compilation

# Compile a single file
tsc app.ts
# Produces app.js in the same directory

# Compile with a specific target
tsc --target ES2020 app.ts

# Compile an entire project using tsconfig.json
tsc

# Watch mode for development
tsc --watch

tsconfig.json Configuration

A well-configured tsconfig.json controls exactly how TypeScript is converted to JavaScript. Here are the key compiler options relevant to JS output:

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "outDir": "./dist",
    "rootDir": "./src",
    "declaration": true,
    "declarationDir": "./dist/types",
    "sourceMap": true,
    "removeComments": false,
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist", "**/*.test.ts"]
}
OptionEffect on JS Output
targetControls which ES version the output uses (ES5, ES2015, ES2020, ESNext)
moduleSets the module system: CommonJS (require), ESNext (import)
declarationGenerates .d.ts files alongside JS output
sourceMapGenerates .js.map files for debugging
removeCommentsStrips all comments from output JS
outDirDirectory where compiled JS files are written

Example: TypeScript Input vs JavaScript Output

TypeScript Input:

interface User {
  id: number;
  name: string;
  email: string;
  isActive: boolean;
}

type Role = 'admin' | 'editor' | 'viewer';

function greetUser(user: User, role: Role): string {
  const greeting: string = `Hello, ${user.name}!`;
  return `${greeting} You are logged in as ${role}.`;
}

const users: User[] = [
  { id: 1, name: 'Alice', email: 'alice@example.com', isActive: true },
  { id: 2, name: 'Bob', email: 'bob@example.com', isActive: false },
];

const activeUsers: User[] = users.filter(
  (user: User): boolean => user.isActive
);

export { greetUser, activeUsers };

JavaScript Output (ES2020 target):

function greetUser(user, role) {
  const greeting = `Hello, ${user.name}!`;
  return `${greeting} You are logged in as ${role}.`;
}

const users = [
  { id: 1, name: 'Alice', email: 'alice@example.com', isActive: true },
  { id: 2, name: 'Bob', email: 'bob@example.com', isActive: false },
];

const activeUsers = users.filter(
  (user) => user.isActive
);

export { greetUser, activeUsers };

Notice how the interface, type alias, and all type annotations are completely removed. The runtime logic remains identical. This is the fundamental operation of any TypeScript to JavaScript converter.

Method 2: Online Converter Tools

When you need a quick conversion without installing anything, an online converter is the fastest path. Our TypeScript to JavaScript online converter handles the full TypeScript syntax including generics, enums, interfaces, type guards, and decorators.

When to use an online converter:

  • Quick one-off conversions while learning or debugging
  • Converting code snippets from TS documentation or Stack Overflow answers
  • Sharing JavaScript versions of TypeScript examples with team members who do not use TS
  • Verifying what JavaScript output the TypeScript compiler would produce
  • Converting single files without setting up a build pipeline

You can also use our TS to JS converter which provides the same functionality with additional formatting options. Both tools run entirely in your browser, so your code never leaves your machine.

Method 3: Babel for TypeScript Stripping

Babel can strip TypeScript types using the @babel/preset-typescript preset. This approach is ideal when you already have a Babel-based build pipeline and want to add TypeScript support without replacing your existing setup.

Installation

npm install --save-dev @babel/core @babel/cli \
  @babel/preset-env @babel/preset-typescript

babel.config.json

{
  "presets": [
    ["@babel/preset-env", { "targets": "> 0.25%, not dead" }],
    "@babel/preset-typescript"
  ]
}

Usage

# Compile a single file
npx babel src/app.ts --out-file dist/app.js

# Compile entire directory
npx babel src --out-dir dist --extensions ".ts,.tsx"

# Watch mode
npx babel src --out-dir dist --extensions ".ts,.tsx" --watch

Important limitation: Babel does not perform type checking. It only strips types. This means type errors in your TypeScript code will not be caught during the Babel compilation step. You should run tsc --noEmit separately (for example, in your CI pipeline or as a pre-commit hook) to catch type errors.

Babel also cannot handle certain TypeScript-specific features that require type information:

  • const enum declarations (Babel replaces them with regular enums)
  • namespace merging across files
  • Legacy export = syntax

Method 4: esbuild (Fastest Approach)

esbuild is a JavaScript bundler written in Go that compiles TypeScript to JavaScript at extraordinary speed. It is typically 10-100x faster than tsc and is the engine powering Vite during development. If build speed is your primary concern, esbuild is the best choice.

Installation and Basic Usage

npm install --save-dev esbuild

# Transform a single file (type-strip only)
npx esbuild src/app.ts --outfile=dist/app.js

# Bundle with tree-shaking
npx esbuild src/index.ts --bundle --outfile=dist/bundle.js \
  --format=esm --target=es2020

# Multiple entry points
npx esbuild src/index.ts src/worker.ts \
  --outdir=dist --format=esm

Programmatic API

import { build } from 'esbuild';

await build({
  entryPoints: ['src/index.ts'],
  bundle: true,
  outfile: 'dist/bundle.js',
  format: 'esm',
  target: 'es2020',
  sourcemap: true,
  minify: process.env.NODE_ENV === 'production',
  treeShaking: true,
});

Like Babel, esbuild performs type stripping only. It does not validate types. Run tsc --noEmit separately for type checking. esbuild also does not support const enum or legacy namespace merging.

Performance Comparison

Tool1,000 FilesType CheckingLanguage
tsc~15-30sYes (full)TypeScript (JS)
babel~8-15sNoJavaScript
esbuild~0.3-1sNoGo
swc~0.5-1.5sNoRust

Method 5: SWC -- Rust-Based Speed

SWC (Speedy Web Compiler) is a Rust-based JavaScript/TypeScript compiler that offers performance comparable to esbuild. It is the default compiler in Next.js and is used by tools like Parcel and Deno. SWC supports a broader range of TypeScript features than esbuild, including decorators.

Installation and Usage

npm install --save-dev @swc/core @swc/cli

# Compile a single file
npx swc src/app.ts -o dist/app.js

# Compile a directory
npx swc src --out-dir dist

# Watch mode
npx swc src --out-dir dist --watch

.swcrc Configuration

{
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "tsx": true,
      "decorators": true,
      "dynamicImport": true
    },
    "transform": {
      "legacyDecorator": true,
      "decoratorMetadata": true
    },
    "target": "es2020"
  },
  "module": {
    "type": "es6"
  },
  "sourceMaps": true
}

SWC advantages over esbuild:

  • Full decorator support (both legacy and TC39 Stage 3)
  • Better const enum handling via plugin system
  • Used by Next.js, so it is battle-tested at scale
  • Plugin system for custom transformations

Handling Common Conversion Challenges

Not all TypeScript features are simple type annotations that can be erased. Some TypeScript constructs emit runtime JavaScript code and require careful handling during conversion.

Enums

TypeScript enums compile to JavaScript objects with forward and reverse mappings. This is one of the few TypeScript features that produces new runtime code rather than just type annotations:

TypeScript:

enum Direction {
  Up = 'UP',
  Down = 'DOWN',
  Left = 'LEFT',
  Right = 'RIGHT',
}

enum StatusCode {
  OK = 200,
  NotFound = 404,
  ServerError = 500,
}

function move(direction: Direction): void {
  console.log(`Moving ${direction}`);
}

Compiled JavaScript:

var Direction;
(function (Direction) {
  Direction["Up"] = "UP";
  Direction["Down"] = "DOWN";
  Direction["Left"] = "LEFT";
  Direction["Right"] = "RIGHT";
})(Direction || (Direction = {}));

var StatusCode;
(function (StatusCode) {
  StatusCode[StatusCode["OK"] = 200] = "OK";
  StatusCode[StatusCode["NotFound"] = 404] = "NotFound";
  StatusCode[StatusCode["ServerError"] = 500] = "ServerError";
})(StatusCode || (StatusCode = {}));

function move(direction) {
  console.log(`Moving ${direction}`);
}

const enum caveat: The const enum keyword tells TypeScript to inline enum values at compile time rather than creating a runtime object. Only tsc handles this correctly. Babel and esbuild convert const enum to regular enum, which changes the runtime behavior and bundle size.

Decorators

TypeScript decorators (commonly used with Angular, NestJS, and TypeORM) generate complex JavaScript wrapper functions:

// TypeScript with decorators
function Log(target: any, key: string, descriptor: PropertyDescriptor) {
  const original = descriptor.value;
  descriptor.value = function (...args: any[]) {
    console.log(`Calling ${key} with`, args);
    return original.apply(this, args);
  };
}

class Calculator {
  @Log
  add(a: number, b: number): number {
    return a + b;
  }
}

To compile decorators you need either tsc with experimentalDecorators: true or SWC with legacyDecorator: true. esbuild has limited decorator support. If your codebase uses decorators extensively, SWC or tsc are the recommended converters.

Namespaces

TypeScript namespaces (formerly called internal modules) compile to immediately-invoked function expressions (IIFEs):

// TypeScript
namespace Validation {
  export interface StringValidator {
    isValid(s: string): boolean;
  }

  export class EmailValidator implements StringValidator {
    isValid(s: string): boolean {
      return /^[^@]+@[^@]+$/.test(s);
    }
  }
}

// Compiled JavaScript
var Validation;
(function (Validation) {
  class EmailValidator {
    isValid(s) {
      return /^[^@]+@[^@]+$/.test(s);
    }
  }
  Validation.EmailValidator = EmailValidator;
})(Validation || (Validation = {}));

TypeScript Features That Do Not Exist in JavaScript

Understanding which TypeScript features have JavaScript equivalents and which are purely compile-time helps you predict the output of any TypeScript to JavaScript converter:

FeatureCompile-Time Only?JS Output
interfaceYesCompletely removed
type aliasYesCompletely removed
Type annotations (: string)YesStripped
Generics (<T>)YesStripped
as type assertionYesStripped
enumNoIIFE creating runtime object
const enumPartially (inlined by tsc)Inlined values or IIFE (depends on tool)
namespaceNoIIFE wrapper
DecoratorsNoHelper function calls
Parameter propertiesNoConstructor assignments
import typeYesCompletely removed

Parameter properties are a common surprise. TypeScript allows shorthand constructor parameter declarations that generate property assignments:

// TypeScript
class Service {
  constructor(
    private readonly name: string,
    public port: number,
    protected host: string = 'localhost'
  ) {}
}

// Compiled JavaScript
class Service {
  constructor(name, port, host = 'localhost') {
    this.name = name;
    this.port = port;
    this.host = host;
  }
}

Preserving JSDoc Comments for IDE Support

When you remove types from TypeScript and convert to JavaScript, you lose IDE IntelliSense, autocomplete, and inline documentation. JSDoc comments can restore much of this functionality in plain JavaScript files:

// TypeScript original
interface Config {
  host: string;
  port: number;
  debug?: boolean;
}

function createServer(config: Config): void {
  // ...
}

// JavaScript with JSDoc (preserves IDE support)
/**
 * @typedef {Object} Config
 * @property {string} host - Server hostname
 * @property {number} port - Port number
 * @property {boolean} [debug] - Enable debug mode
 */

/**
 * Creates a new server instance.
 * @param {Config} config - Server configuration
 * @returns {void}
 */
function createServer(config) {
  // ...
}

You can even enable TypeScript checking on JSDoc-annotated JavaScript files by adding // @ts-check at the top of the file or setting "checkJs": true in your tsconfig.json. This gives you a gradual migration path in both directions.

Automating JSDoc Generation

Tools like ts-to-jsdoc and typescript-to-jsdoc can automatically convert TypeScript type annotations to JSDoc comments during the conversion process. This is valuable when migrating a project away from TypeScript while preserving developer experience:

# Using ts-to-jsdoc
npx ts-to-jsdoc src/ --out-dir dist/

# The output JavaScript will include JSDoc equivalents
# of all TypeScript type annotations

Build Pipeline Integration

Modern web applications use bundlers that handle TypeScript compilation as part of the build pipeline. Here is how the most popular tools integrate TypeScript-to-JavaScript conversion:

Vite

Vite uses esbuild for TypeScript compilation during development and Rollup for production builds. TypeScript works out of the box with zero configuration:

// vite.config.ts
import { defineConfig } from 'vite';

export default defineConfig({
  // TypeScript works out of the box
  // esbuild handles TS compilation in dev
  esbuild: {
    target: 'es2020',
    // Customize esbuild TypeScript options
    tsconfigRaw: {
      compilerOptions: {
        experimentalDecorators: true,
      },
    },
  },
  build: {
    target: 'es2020',
    // Rollup handles production builds
    rollupOptions: {
      // ...
    },
  },
});

For type checking during Vite builds, install vite-plugin-checker:

npm install --save-dev vite-plugin-checker

// vite.config.ts
import checker from 'vite-plugin-checker';

export default defineConfig({
  plugins: [
    checker({ typescript: true }),
  ],
});

webpack

webpack requires a loader to process TypeScript files. The two main options are ts-loader (uses tsc) and babel-loader with @babel/preset-typescript:

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

// webpack.config.js — Option 2: esbuild-loader (fastest)
const { EsbuildPlugin } = require('esbuild-loader');

module.exports = {
  entry: './src/index.ts',
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        loader: 'esbuild-loader',
        options: {
          target: 'es2020',
        },
      },
    ],
  },
  plugins: [new EsbuildPlugin({ target: 'es2020' })],
  resolve: {
    extensions: ['.tsx', '.ts', '.js'],
  },
};

Rollup

Rollup is commonly used for building libraries. The @rollup/plugin-typescript or rollup-plugin-esbuild handles TypeScript compilation:

// rollup.config.js — using esbuild (recommended)
import esbuild from 'rollup-plugin-esbuild';

export default {
  input: 'src/index.ts',
  output: [
    { file: 'dist/index.cjs', format: 'cjs' },
    { file: 'dist/index.mjs', format: 'esm' },
  ],
  plugins: [
    esbuild({
      target: 'es2020',
      sourceMap: true,
      minify: false,
    }),
  ],
};

Choosing the Right Conversion Method

The best method depends on your specific requirements. Here is a decision guide:

ScenarioRecommended ToolReason
Publishing an npm librarytscGenerates .d.ts declaration files alongside JS
Quick one-off conversionOnline converterNo installation needed, instant results
Existing Babel pipeline@babel/preset-typescriptIntegrates with existing Babel plugins
Maximum build speedesbuild10-100x faster than tsc, powers Vite
Decorator-heavy code (Angular/NestJS)swc or tscFull decorator transform support
Next.js projectswc (built-in)Default compiler, zero config needed
Full project migration from TS to JStsc + ts-to-jsdocPreserves IDE support via JSDoc

Step-by-Step: Bulk Convert a TypeScript Project to JavaScript

If you need to convert an entire TypeScript project to JavaScript, follow this systematic approach:

  1. Audit your TypeScript features: Check if you use enum, namespace, decorators, or const enum. These affect which tool you can use.
  2. Compile with tsc first: Run tsc --outDir dist to generate baseline JavaScript output. This confirms your code compiles cleanly.
  3. Generate JSDoc annotations: If preserving IDE support matters, run ts-to-jsdoc to convert type annotations to JSDoc comments.
  4. Rename files: Change all .ts to .js and .tsx to .jsx (or .js if your bundler supports it).
  5. Remove tsconfig.json: Replace with a jsconfig.json if you want path aliases and module resolution hints for your IDE.
  6. Update package.json: Remove typescript and @types/* dev dependencies. Update build scripts to remove the tsc step.
  7. Test thoroughly: Run your entire test suite to verify that the converted JavaScript behaves identically to the original TypeScript.
# Quick bulk conversion script
#!/bin/bash

# 1. Compile TypeScript to JavaScript
tsc --outDir dist --declaration false --sourceMap false

# 2. Copy non-TS files
rsync -av --exclude='*.ts' --exclude='*.tsx' src/ dist/

# 3. Verify output
node dist/index.js

echo "Conversion complete. Check dist/ directory."

Common Errors and Troubleshooting

Here are the most frequent issues developers encounter when converting TypeScript to JavaScript, along with their solutions:

Error: Cannot find module

// Problem: TypeScript path aliases don't resolve in JS
import { utils } from '@/lib/utils';

// Solution: Use relative paths or configure module resolution
import { utils } from '../lib/utils.js';

// Or configure jsconfig.json paths
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    }
  }
}

Error: Unexpected token (enum/namespace)

// Problem: Babel/esbuild encounters const enum
const enum Color { Red, Green, Blue }

// Solution 1: Replace const enum with regular enum
enum Color { Red, Green, Blue }

// Solution 2: Replace with a plain object
const Color = {
  Red: 0,
  Green: 1,
  Blue: 2,
} as const;
// In JS (after conversion):
const Color = { Red: 0, Green: 1, Blue: 2 };

Error: File extension issues with ESM

// Problem: Node.js ESM requires .js extensions
import { helper } from './helper';
// Error: Cannot find module './helper'

// Solution: Add explicit .js extensions
import { helper } from './helper.js';
// This works even when the source file is helper.ts

// In tsconfig.json, set:
{
  "compilerOptions": {
    "moduleResolution": "nodenext",
    "module": "nodenext"
  }
}

Frequently Asked Questions

Can I convert TypeScript to JavaScript without installing anything?

Yes. Use our online TypeScript to JavaScript converter which runs entirely in your browser. Paste your TypeScript code and get clean JavaScript output instantly. No npm packages, no build tools, no command line required.

Does converting TypeScript to JavaScript change the runtime behavior?

For pure type annotations (interfaces, type aliases, generics), removing them has zero effect on runtime behavior. However, enums, namespaces, parameter properties, and decorators produce runtime JavaScript code. The conversion of these features can produce slightly different output depending on which tool you use, though the intended behavior should remain the same.

What is the fastest way to compile TypeScript?

esbuild is the fastest TypeScript compiler, processing thousands of files in under a second. It is written in Go and performs only type stripping without type checking. For projects that need both speed and type safety, run esbuild for compilation and tsc --noEmit for type checking in parallel.

Should I use tsc or esbuild for my project?

Use tsc when you need declaration file generation (.d.ts), full const enum support, or namespace merging. Use esbuild when build speed is critical and you handle type checking separately. Many projects use both: esbuild for fast development builds and tsc for CI/CD type checking and declaration generation.

How do I preserve IntelliSense after removing TypeScript?

Add JSDoc comments to your JavaScript files. Modern IDEs like VS Code read JSDoc annotations and provide autocomplete, type hints, and inline documentation. You can even enable type checking on JS files with // @ts-check or "checkJs": true in jsconfig.json.

Can Babel handle all TypeScript features?

Babel handles most TypeScript features but has limitations with const enum (treats as regular enum), namespace merging across files, and the legacy export = syntax. For most projects, these limitations are not relevant. If your codebase uses these features extensively, use tsc or SWC instead.

What is the difference between ts-to-js-converter tools and the TypeScript compiler?

Online TS to JS converter tools and the tsc compiler perform the same fundamental operation: removing TypeScript-specific syntax to produce valid JavaScript. Online tools are convenient for quick conversions, while tsc is designed for project-wide compilation with configuration, source maps, and declaration file output.

For a deeper comparison of when to use TypeScript versus JavaScript, see our guide on TypeScript vs JavaScript: When to Convert.

𝕏 Twitterin LinkedIn
บทความนี้มีประโยชน์ไหม?

อัปเดตข่าวสาร

รับเคล็ดลับการพัฒนาและเครื่องมือใหม่ทุกสัปดาห์

ไม่มีสแปม ยกเลิกได้ตลอดเวลา

ลองเครื่องมือที่เกี่ยวข้อง

JSTypeScript to JavaScriptT→JTypeScript to JavaScript Converter Online

บทความที่เกี่ยวข้อง

TypeScript vs JavaScript: เมื่อไหร่และวิธีการแปลง

คู่มือเชิงปฏิบัติสำหรับการตัดสินใจว่าเมื่อไหร่ควรแปลง TypeScript เป็น JavaScript และในทางกลับกัน ครอบคลุมกลยุทธ์การย้าย เครื่องมือ ผลกระทบต่อขนาด bundle และข้อพิจารณาของทีม

JSON เป็น TypeScript: คู่มือฉบับสมบูรณ์พร้อมตัวอย่าง

เรียนรู้วิธีแปลงข้อมูล JSON เป็น interface ของ TypeScript โดยอัตโนมัติ ครอบคลุม nested objects, arrays, optional fields และแนวทางปฏิบัติที่ดี