Menu

Como rodar um arquivo TypeScript: tsc, Node.js, tsx, ts-node

Cinco jeitos de rodar um arquivo .ts: compilar com tsc e rodar o JavaScript, rodar direto com node arquivo.ts (type stripping), usar tsx ou ts-node, ou usar Deno e Bun. Quais verificam tipos, que sintaxe cada um aceita e qual escolher.

Esta página tem editores executáveis - edite, execute e veja a saída na hora.

Um arquivo TypeScript não roda do jeito que está, porque navegadores e engines JavaScript não entendem anotações de tipo. Alguma coisa precisa remover os tipos antes. Essa coisa é o compilador do TypeScript (tsc), que também verifica os tipos, ou uma ferramenta mais rápida que só os remove. O jeito mais rápido de rodar o código desta página é o botão Run:

Saída:

[x] Install TypeScript
[ ] Run a .ts file

Todo bloco executável destas docs funciona do mesmo jeito: o código é verificado pelo TypeScript 7 com strict ligado e só roda se não houver erros de tipo. Para experimentos mais longos, o playground de TypeScript é o mesmo editor em uma página própria. O resto desta página trata de rodar arquivos .ts na sua própria máquina.

As opções em resumo

ComandoVerifica tiposPrecisa de buildAceita enum, namespace, parameter properties
npx tsc e depois node dist/index.jsSimSimSim
node index.ts (Node.js 22.18+, 23.6+)NãoNãoNão
npx tsx index.tsNãoNãoSim
npx ts-node index.tsSimNãoSim, mas não com o TypeScript 7
deno run index.tsNão (o deno check verifica)NãoSim
bun index.tsNãoNãoSim

A coluna que surpreende é a primeira: a maioria das opções rápidas roda código que tem erros de tipo. Um projeto típico roda o código com uma delas e roda o tsc --noEmit à parte, no editor e no CI, para pegar os erros.

Compilar com tsc e rodar com Node

Esta abordagem funciona em qualquer lugar e verifica tudo. Com o TypeScript instalado no projeto e um tsconfig.json que define "rootDir": "./src" e "outDir": "./dist":

npx tsc
node dist/index.js

O tsc verifica os tipos de todos os arquivos e depois grava arquivos .js em dist. Para um arquivo solto, sem projeto, passe o nome do arquivo. Aí ele usa as opções padrão e grava index.js ao lado de index.ts:

npx tsc index.ts
node index.js

(Se a pasta tiver um tsconfig.json, o tsc recusa nomes de arquivo com error TS5112; rode apenas npx tsc, ou adicione --ignoreConfig.)

Por padrão o tsc grava o JavaScript mesmo quando há erros de tipo, então o node pode rodar um programa que falhou na verificação. Adicione "noEmitOnError": true à configuração para evitar isso, ou encadeie os comandos em um script para que o segundo passo só rode se o primeiro der certo:

{
    "scripts": {
        "build": "tsc",
        "start": "tsc && node dist/index.js"
    }
}

Durante o desenvolvimento, npx tsc --watch recompila a cada vez que você salva.

Rodar TypeScript diretamente com Node.js

O Node.js atual roda arquivos .ts por conta própria:

node index.ts

O Node remove as anotações de tipo, trocando-as por espaços em branco para que os números de linha nos stack traces continuem batendo, e roda o que sobra. Isso vem ligado por padrão desde o Node.js 23.6.0 e 22.18.0, não mostra aviso desde o 24.3.0 e 22.18.0 e foi marcado como estável no Node.js 24.12.0 e 25.2.0. Versões anteriores que têm o recurso (22.6 a 22.17 e 23.0 a 23.5) precisam da flag: node --experimental-strip-types index.ts.

Quatro regras vêm junto:

  • Nenhuma verificação de tipos. Um arquivo com const age: number = "forty" roda e imprime forty.
  • Só sintaxe apagável. Tudo o que precisa virar código JavaScript, em vez de sumir, é rejeitado: enum, blocos namespace com código de runtime, parameter properties no construtor como constructor(private name: string) e aliases import x = require(). O Node para com SyntaxError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]: TypeScript enum is not supported in strip-only mode.
  • O tsconfig.json é ignorado. Opções como paths ou target não têm efeito.
  • Imports precisam de nomes de arquivo reais. Escreva import { add } from "./math.ts", com a extensão, e marque imports só de tipo com type: import { add, type Pair } from "./math.ts". Sem type, o Node procura um export de runtime chamado Pair e falha com SyntaxError: The requested module './math.ts' does not provide an export named 'Pair'.

Duas opções do compilador fazem o tsc aplicar as mesmas regras, para que o editor avise antes do Node: "erasableSyntaxOnly": true aponta error TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled. em um enum, e "verbatimModuleSyntax": true exige a palavra type em imports só de tipo. Para continuar escrevendo extensões .ts nos imports e ainda compilar com tsc, adicione "rewriteRelativeImportExtensions": true, que transforma ./math.ts em ./math.js na saída.

O Node.js 24 também tem --experimental-transform-types, que gera código para enums e parameter properties em vez de rejeitá-los. Ele mostra um ExperimentalWarning, e o Node.js 26 removeu a flag, então não construa nada em cima dela.

Este bloco usa dois recursos que o node index.ts rejeita. Ele roda aqui porque o editor o compila com o compilador do TypeScript, que gera JavaScript para os dois:

A versão apagável do mesmo código usa um objeto const e um campo comum, que o Node consegue rodar como está:

tsx

O tsx roda um arquivo TypeScript em um passo, sem configuração e sem restrições de sintaxe:

npm install --save-dev tsx
npx tsx index.ts
npx tsx watch index.ts   # rerun on every change

Ele transforma o código com esbuild, então enums, namespaces e parameter properties funcionam, e imports sem extensão são resolvidos como em um bundler. Assim como o type stripping do Node, ele não verifica tipos. É a escolha comum para scripts, servidores de desenvolvimento e testes em versões do Node.js anteriores ao type stripping, ou quando o código usa sintaxe que o Node rejeita.

ts-node

O ts-node foi durante anos o jeito padrão de rodar TypeScript no Node.js, e ainda é o que muitos tutoriais e projetos antigos usam (npx ts-node index.ts, node -r ts-node/register). Ele verifica tipos por padrão, usando a API JavaScript do compilador do TypeScript.

Essa API é justamente o que o TypeScript 7 não traz: o compilador dele é um programa nativo, e o pacote typescript 7 não expõe nenhuma API de compilador para JavaScript. Com o TypeScript 7 instalado, o ts-node quebra antes de rodar qualquer coisa:

TypeError: Cannot read properties of undefined (reading 'fileExists')
    at readConfig (/project/node_modules/ts-node/dist/configuration.js:91:33)

A última versão do ts-node, a 10.9.2, é de dezembro de 2023. Para código novo, use tsx ou node index.ts. Uma configuração existente que depende do ts-node continua funcionando se o projeto ficar no TypeScript 6 (npm install --save-dev typescript@6) e tiver um tsconfig.json, mesmo que vazio, {}. Sem ele, o ts-node usa padrões embutidos que incluem a module resolution node10, descontinuada no TypeScript 6, e npx ts-node index.ts termina sem rodar o arquivo e sem mostrar erro.

Deno e Bun

Os dois runtimes tratam TypeScript como um tipo de arquivo de primeira classe:

deno run index.ts    # runs without checking
deno check index.ts  # type-checks, reports errors, runs nothing

bun index.ts         # runs without checking

Nenhum dos dois precisa do typescript instalado nem de um tsconfig.json, e ambos aceitam enum e os outros recursos não apagáveis. O Deno traz a própria cópia do compilador do TypeScript para o deno check. O Bun só remove tipos, então em um projeto Bun você ainda instala o typescript e roda tsc --noEmit para encontrar erros de tipo.

Erros de tipo só param o programa com tsc

Só os caminhos que rodam o tsc antes se recusam a executar um programa com erros de tipo. O editor desta página é um deles, então este bloco para no compilador:

index.ts(6,21): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.

Salvo como arquivo e rodado com node index.ts, npx tsx index.ts ou bun index.ts, o mesmo código roda e imprime 12, porque 3 * "4" converte a string. É por isso que vale manter o tsc --noEmit no fluxo mesmo quando uma ferramenta mais rápida roda o código:

{
    "scripts": {
        "dev": "tsx watch src/index.ts",
        "typecheck": "tsc --noEmit"
    }
}

Qual usar?

  • Aprendendo, ou um teste rápido: o botão Run destas páginas, ou o playground.
  • Um script ou ferramenta pequena em um Node.js atual: node index.ts, com erasableSyntaxOnly na configuração para que o editor aponte tudo o que o Node rejeitaria.
  • Qualquer projeto Node.js, qualquer sintaxe: tsx para rodar, tsc --noEmit para verificar.
  • Uma biblioteca ou qualquer coisa que você publica: tsc, porque ele também grava os arquivos .d.ts de que os usuários precisam.
  • Código de front end: o seu bundler ou framework (Vite, Next.js, Angular CLI) roda o TypeScript para você; adicione tsc --noEmit para a verificação.

Perguntas frequentes

Como rodar um arquivo TypeScript?

O jeito clássico tem dois passos: npx tsc compila .ts para .js e depois node dist/index.js roda a saída. No Node.js 22.18 ou 23.6 e posteriores você também pode rodar node index.ts diretamente, desde que o arquivo só use sintaxe de tipo que possa ser apagada. npx tsx index.ts roda qualquer arquivo TypeScript em um passo.

O Node.js consegue rodar TypeScript diretamente?

Sim. Desde o Node.js 23.6 e 22.18, node file.ts funciona sem flags: o Node remove as anotações de tipo e roda o resto. Ele não verifica tipos, ignora o tsconfig.json e rejeita sintaxe que precisa gerar código, como enum, namespace com código de runtime e parameter properties no construtor.

O ts-node funciona com o TypeScript 7?

Não. O ts-node chama a API JavaScript do compilador, que o pacote typescript 7 não fornece, então ele quebra ao iniciar (Cannot read properties of undefined (reading 'fileExists')). A última versão é a 10.9.2, de dezembro de 2023. Use tsx, o type stripping do próprio Node, ou mantenha o ts-node com o TypeScript 6.

Qual é a diferença entre tsx e ts-node?

O tsx só remove os tipos (com esbuild) e roda o resultado, então inicia rápido e nunca reporta erros de tipo. O ts-node verifica tipos por padrão usando o compilador do TypeScript, o que o deixa mais lento e o prende à API JavaScript do compilador. A maioria dos projetos hoje combina tsx ou node file.ts para rodar com tsc --noEmit para verificar.

Existe um sandbox de TypeScript online?

Sim. Os blocos de código destas páginas e o playground de TypeScript da Coddy compilam o seu código com o TypeScript 7 e o executam, mostrando os erros do compilador ou a saída do programa. O TypeScript Playground oficial, em typescriptlang.org, mostra o JavaScript gerado e os erros.

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR