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
| Comando | Verifica tipos | Precisa de build | Aceita enum, namespace, parameter properties |
|---|---|---|---|
npx tsc e depois node dist/index.js | Sim | Sim | Sim |
node index.ts (Node.js 22.18+, 23.6+) | Não | Não | Não |
npx tsx index.ts | Não | Não | Sim |
npx ts-node index.ts | Sim | Não | Sim, mas não com o TypeScript 7 |
deno run index.ts | Não (o deno check verifica) | Não | Sim |
bun index.ts | Não | Não | Sim |
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 imprimeforty. - Só sintaxe apagável. Tudo o que precisa virar código JavaScript, em vez de sumir, é rejeitado:
enum, blocosnamespacecom código de runtime, parameter properties no construtor comoconstructor(private name: string)e aliasesimport x = require(). O Node para comSyntaxError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]: TypeScript enum is not supported in strip-only mode. - O
tsconfig.jsoné ignorado. Opções comopathsoutargetnã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 comtype:import { add, type Pair } from "./math.ts". Semtype, o Node procura um export de runtime chamadoPaire falha comSyntaxError: 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, comerasableSyntaxOnlyna configuração para que o editor aponte tudo o que o Node rejeitaria. - Qualquer projeto Node.js, qualquer sintaxe:
tsxpara rodar,tsc --noEmitpara verificar. - Uma biblioteca ou qualquer coisa que você publica:
tsc, porque ele também grava os arquivos.d.tsde 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 --noEmitpara 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.