Can TypeScript and JavaScript Be Used Together?

Learn how to co-use TypeScript and JavaScript in a single project, enabling progressive typing, interop with JS modules, and practical patterns for frontend and Node environments.

JavaScripting
JavaScripting Team
·5 min read
Quick AnswerDefinition

TypeScript and JavaScript can be used together in the same project because TypeScript is a superset of JavaScript that compiles to plain JS. You can progressively adopt TS by enabling allowJs and checkJs, importing JS modules into TS, and adding .d.ts declarations for libraries. This approach lets teams gain type safety without rewriting existing code.

Can TypeScript and JavaScript Be Used Together? An Overview

TypeScript is a strict syntactic superset of JavaScript, which means any valid JS is valid TS. This makes interop natural: you can host TS files in the same project with JS files, share data structures, and progressively adopt typed code. In practice, you can start by enabling allowJs, then gradually add type declarations while leaving existing JS untouched. The question often asked is can typescript and javascript be used together, and the answer is yes with a clear path. In this section, we’ll outline the core patterns, the trade-offs, and the tooling you’ll rely on in both frontend frameworks (React/Vue/Svelte) and Node environments. We'll also discuss common pitfalls and how to avoid them as you grow a mixed codebase.

TypeScript
// main.ts import { greet } from './lib.js'; // importing a JS module from TS const m: string = greet('World'); console.log(m);
JavaScript
// lib.js export function greet(name) { return `Hello, ${name}!`; }

As you start mixing TS and JS, you’ll notice the ability to gradually introduce types while reusing existing JavaScript. This approach reduces risk and accelerates adoption. You can also layer in type declarations for JS libraries to improve editor hints and compile-time checks. This section will show you concrete patterns, so you can ship features faster without breaking existing behavior.

prerequisites_difference_note_1_placeholder_for_compatibility_avoidance_0-null_placeholder_0]:null},

Steps

Estimated time: 2-4 hours

  1. 1

    Audit codebase for interop readiness

    Scan your codebase to identify pure JS files that may be good candidates for progressive typing and note any strongly typed interfaces you’ll want to expose to TS. Create a small scope for experiments (e.g., a shared utility folder).

    Tip: Start with a non-critical module to validate import paths and module resolution.
  2. 2

    Enable allowJs and checkJs

    Turn on allowJs to let TS see JS files and checkJs to type-check JS using JSDoc or inferred types. Update tsconfig.json with these flags and ensure your editor and build pipeline pick up the changes.

    Tip: Run tsc --noEmit to confirm type checks without creating output files.
  3. 3

    Import JS modules into TS

    Create a tiny TS module that imports a JS function and uses it with explicit types. This confirms that the interop surface behaves as expected in your target environment.

    Tip: Prefer explicit types for function inputs/outputs to surface type issues early.
  4. 4

    Add .d.ts declarations for JS libraries

    For JS libraries without typings, write minimal .d.ts files to describe the public API and enable editor/compile-time safety in TS code.

    Tip: Keep declarations narrow and update as APIs evolve.
  5. 5

    Progressively convert utilities to TS

    Rename JS files to .ts or .tsx gradually and replace inferred types with explicit ones. Maintain tests to verify behavior during migration.

    Tip: Convert one module at a time to limit blast radius.
  6. 6

    Tighten tooling and tests

    Add type-aware tests (ts-jest or similar) and ensure CI runs type-checks on both TS and JS. Fine-tune moduleResolution and lib configurations as needed.

    Tip: Reproduce common runtime scenarios in tests to catch interop issues early.
Pro Tip: Use tsconfig.json option allowJs to enable gradual interop without breaking existing JS.
Warning: Be mindful of dynamic JS typing; use checkJs and explicit declarations to catch issues.
Note: Add .d.ts declarations for non-typed libraries to improve editor support and safety.

Prerequisites

Required

Optional

  • VS Code or any code editor with TS/JS support
    Optional
  • Familiarity with ES modules (ESM) and CJS
    Optional

Commands

ActionCommand
Initialize a TS projectCreates a baseline tsconfig.json for interopnpx tsc --init
Compile TS to JSBuild TS sources into JS output according to tsconfig.jsonnpm run build
Check JS with TSType-checks JS files with checkJs enablednpx tsc --noEmit
Install types for a JS libraryAdds TS declarations for a JS library when typings are missingnpm install --save-dev @types/legacy-lib
Run a quick TS+JS reproExecute the built JS to verify runtime behaviornode dist/main.js

Questions & Answers

Can I import a JavaScript file into a TypeScript file?

Yes. You can import a .js module into a .ts file by using ES module syntax and enabling allowJs in tsconfig. This lets you reuse existing JS code while adding type information over time.

Yes, you can import JS modules into TS files as you gradually add types.

Do I need to rewrite all JavaScript to TypeScript to benefit?

No. You can progressively adopt TypeScript by enabling allowJs and checkJs, converting modules one by one, and only rewriting what benefits most.

No need to rewrite everything at once; start small and expand gradually.

How do I declare types for a JavaScript library?

Create a .d.ts declaration file describing the module’s API, or install community typings if available. This enables TS to type-check your usage of the library.

Add a declaration file or typings for your JS library so TS can understand it.

Which config flags matter most for interop?

Key flags include allowJs, checkJs, esModuleInterop, and moduleResolution. They govern how TS sees JS files and how modules are resolved.

Enable allowJs and checkJs to start interop, then adjust module settings as needed.

Are there performance implications from mixing TS and JS?

Interoperability itself has minimal runtime cost. Build tooling and bundling strategies determine performance. Focus on efficient bundling and tree-shaking for production.

No significant runtime cost from TS/JS interop; optimize your build workflow.

What to Remember

  • Can co-exist: TS is a JS superset enabling gradual adoption
  • Enable allowJs and checkJs for safe interop
  • Use .d.ts declarations for JS libraries
  • Prefer ES module syntax for consistency across TS/JS
  • Test both TS and JS code paths to ensure reliability

Related Articles