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.
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.
// main.ts
import { greet } from './lib.js'; // importing a JS module from TS
const m: string = greet('World');
console.log(m);// 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
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
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
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
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
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
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.
Prerequisites
Required
- Required
- npm or yarn package managerRequired
- Required
- Basic knowledge of JavaScript and TypeScriptRequired
Optional
- VS Code or any code editor with TS/JS supportOptional
- Familiarity with ES modules (ESM) and CJSOptional
Commands
| Action | Command |
|---|---|
| Initialize a TS projectCreates a baseline tsconfig.json for interop | npx tsc --init |
| Compile TS to JSBuild TS sources into JS output according to tsconfig.json | npm run build |
| Check JS with TSType-checks JS files with checkJs enabled | npx tsc --noEmit |
| Install types for a JS libraryAdds TS declarations for a JS library when typings are missing | npm install --save-dev @types/legacy-lib |
| Run a quick TS+JS reproExecute the built JS to verify runtime behavior | node 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
