The JS API for the TS7 native port of TypeScript, written in Go and exposed through a Node.js client. This package is a fork of the TypeScript project and publishes under the @nn140 scope.
The programmatic API is in-place compatible with the typescript package from TypeScript 5 and 6 — code written against ts.createProgram, ts.createSourceFile, ts.getPreEmitDiagnostics, ts.sys, etc. runs against the TS7 compiler with little or no change (see Compatibility).
npm install @nn140/typescriptTS7 is the native (Go) port of the TypeScript compiler. The compiler and language service run in a single tsc binary; this package provides the JavaScript client that talks to it over a pipe using a binary protocol. You get:
- The same compiler behavior as
tsc(TS7), with the TS5/TS6 programmatic surface. - An async-first API (
Promise-based) and a sync API (generator-backed), both generated from the same source. - Full access to the native compiler's AST, checker, emitter, and language service via
API.
| Entry point | Description |
|---|---|
@nn140/typescript |
Package metadata: version and versionMajorMinor. |
@nn140/typescript/sync |
Synchronous API (ts.createProgram, ts.createSourceFile, …). |
@nn140/typescript/async |
Async API — every method returns a Promise. |
@nn140/typescript/fs |
FileSystem interface and virtual filesystem helpers. |
@nn140/typescript/proto |
The binary protocol types used to talk to the compiler. |
@nn140/typescript/ast |
AST node types and helpers (re-exported from the API). |
@nn140/typescript/ast/is |
AST node type guards (isIdentifier, isCallExpression, …). |
@nn140/typescript/ast/factory |
AST node factory (createIdentifier, createCall, …). |
@nn140/typescript/ast/scanner |
The scanner. |
@nn140/typescript/ast/visitor |
visitEachChild and friends. |
@nn140/typescript/ast/utils |
AST utilities. |
@nn140/typescript/ast/clone |
AST cloning. |
import { version, versionMajorMinor } from "@nn140/typescript";
version; // "7.3.0" — the published package version
versionMajorMinor; // "7.1" — matches the compiler (tsc --version)The quickest path for ts-node-style tooling is the sync API, which mirrors the TS5/TS6 ts namespace most closely:
import * as ts from "@nn140/typescript/sync";
const program = await ts.createProgram(["main.ts"], {
target: ts.ScriptTarget.ESNext,
module: ts.ModuleKind.NodeNext,
moduleResolution: ts.ModuleResolutionKind.NodeNext,
strict: true,
});
const diagnostics = await ts.getPreEmitDiagnostics(program);
for (const d of diagnostics) {
console.error(ts.flattenDiagnosticMessageText(d.messageText, "\n"));
}The async API is the recommended API for new code:
import * as ts from "@nn140/typescript/async";
const program = await ts.createProgram(["main.ts"], {
target: ts.ScriptTarget.ESNext,
module: ts.ModuleKind.NodeNext,
strict: true,
});
for (const d of await ts.getPreEmitDiagnostics(program)) {
console.error(ts.flattenDiagnosticMessageText(d.messageText, "\n"));
}Both entry points export the same surface; the only difference is that the
async entry point returns Promises.
| Export | Type | Description |
|---|---|---|
version |
string |
The compiler version reported by the TS7 compiler (mirrors ts.version in TS5/TS6 and tsc --version). |
versionMajorMinor |
string |
The major.minor compiler version, e.g. "7.1". |
sys |
System |
A Node-filesystem-backed system host. Mirrors ts.sys from TS5/TS6. |
API |
class |
The TS7 client. Create an instance to access the full compiler surface. |
sys mirrors ts.sys so that host-dependent TS5/TS6 code keeps working:
import { sys } from "@nn140/typescript/sync";
sys.args; // process.argv
sys.getCurrentDirectory(); // process.cwd()
sys.readFile("x.ts"); // string | undefined
sys.fileExists("x.ts");
sys.writeFile("out.js", "text");
sys.getExecutingFilePath();
sys.resolvePath;
sys.getNewLine();
sys.useCaseSensitiveFileNames;API is the full TS7 client. All compiler, checker, emitter, and language
service operations hang off it. A single API instance is a connection to one
tsc --api server process.
import { API } from "@nn140/typescript/sync";
const api = new API({ cwd: process.cwd() });
const program = await api.createProgram(["main.ts"], { strict: true });
const sf = await api.createSourceFile("a.ts", "const x = 1;", {});Constructor options (all optional):
| Option | Description |
|---|---|
tsserverPath |
Path to the tsc executable. Defaults to the binary bundled with the package. |
cwd |
Working directory for the server. Defaults to process.cwd(). |
fs |
A custom FileSystem (from @nn140/typescript/fs) used for virtual filesystems. |
runExternalCode |
Allow trusted projects to execute configured external content mapper processes. |
collectTiming |
Collect per-request timing info, exposed via getTimingInfo(). |
pipe |
(LSP connections) Connect to an existing API pipe instead of spawning a server. |
Use API.fromLSPConnection(options) to attach to an API session provided by an
LSP server.
The following methods on API mirror their TS5/TS6 ts counterparts and are
the ones ts-node-style tooling relies on:
| Method | Mirrors | Notes |
|---|---|---|
createCompilerHost(options?) |
ts.createCompilerHost |
Returns a TS5/TS6-compatible CompilerHost backed by sys. getSourceFile/writeFile are async because TS7 is async-first. |
createSourceFile(fileName, text, options?) |
ts.createSourceFile |
Returns a SourceFile (AST). |
createProgram(rootNames, options, host?, oldProgram?, configFileParsingDiagnostics?) |
ts.createProgram |
TS5/TS6-compatible overload. host is accepted for compatibility; the server performs host duties. A TS7-native (rootFiles, createProgramOptions, oldProgram?, fileChanges?) overload is also provided. |
getPreEmitDiagnostics(sourceFile?) |
ts.getPreEmitDiagnostics |
Config/options + syntactic + global + semantic (+ declaration) diagnostics. |
getDefaultLibFileName(options?) / getDefaultLibFilePath(options?) |
ts.getDefaultLibFileName / ts.getDefaultLibFilePath |
Default library file resolution. |
findConfigFile(searchPath, fileExists?, configName?) |
ts.findConfigFile |
Searches upward for a tsconfig.json. |
getCurrentDirectory() |
ts.sys.getCurrentDirectory |
Server working directory. |
getVersion() |
ts.version |
Compiler version reported by the server. |
createProgram example (TS5/TS6-compatible form):
import { API } from "@nn140/typescript/sync";
const api = new API();
const program = await api.createProgram(
["src/index.ts"],
{ target: api.ScriptTarget.ES2022, module: api.ModuleKind.NodeNext },
/* host */ undefined,
/* oldProgram */ undefined,
/* configFileParsingDiagnostics */ undefined,
);Diagnostics match the TS5/TS6 Diagnostic shape:
import { DiagnosticCategory } from "@nn140/typescript/sync";
for (const d of diagnostics) {
const where = d.file
? `${d.file.fileName}:${d.start !== undefined ? (d.start + 1) : 0}`
: "";
const severity = ["", "error", "warning", "message"][d.category] ?? "";
console.log(`${where} ${severity} TS${d.code}: ${d.messageText}`);
}formatDiagnostics and formatDiagnosticsWithColorAndContext are exported for
TS5/TS6-compatible formatting.
The API exposes the full native AST (Node, SourceFile, Type, Symbol,
Signature), a Checker, an Emitter, and a LanguageService for language
server work. See the ast exports for node kinds, guards, and the factory.
The package aims to cover the TypeScript 5.x programmatic API from the default
export, so import * as ts from "@nn140/typescript/sync" (or
@nn140/typescript/async) works as a drop-in for import * as ts from "typescript". The surface breaks down as follows.
Programs and builders
ts.createProgram(); // ts.createProgram
ts.createIncrementalProgram({ rootNames, options }); // ts.createIncrementalProgram
ts.createBuilderProgram(); // ts.createBuilderProgram
ts.createSemanticDiagnosticsBuilderProgram(); // ts.createSemanticDiagnosticsBuilderProgram
ts.createEmitAndSemanticDiagnosticsBuilderProgram(); // ts.createEmitAndSemanticDiagnosticsBuilderProgram
ts.createCompilerHost(); // ts.createCompilerHost
ts.createIncrementalCompilerHost(); // ts.createIncrementalCompilerHostBuilderProgram mirrors the TS5 builder surface; the builder-creation
functions return a BuilderProgram proxy that exposes the Program surface
plus builder accessors.
Configuration and parsing
ts.createSourceFile(fileName, text, languageVersionOrOptions);
ts.createSourceFileFromText(fileName, text, languageVersionOrOptions); // TS 5.5+
ts.parseJsonText(fileName, text);
ts.parseConfigFileTextToJson(fileName, jsonText); // { error?, config? }
ts.readConfigFile(fileName, readFile);
ts.parseJsonConfigFileContent(json, host, basePath, existingOptions?, configFileName?, resolutionStack?, extraFileExtensions?, extendedConfigCache?);
ts.parseJsonConfigFileContentWorker(json, host, basePath, existingOptions?, configFileName?, resolutionStack?, extraFileExtensions?, extendedConfigCache?);
ts.parseJsonSourceFileConfigFileContent(sourceFile, host, basePath, existingOptions?, configFileName?, resolutionStack?, extraFileExtensions?, extendedConfigCache?);
ts.convertCompilerOptionsFromJson(jsonOptions, basePath, configFileName?);
ts.convertTypeAcquisitionFromJson(jsonOptions, basePath, configFileName?);
ts.getConfigFileParsingDiagnostics(configFileParseResult);Position helpers are available too: getTokenAtPosition,
getLineAndCharacterOfPosition, and getPositionOfLineAndCharacter.
AST factory, printer, and transform
The modern NodeFactory API is exported as ts.factory, and the printer and
transform APIs work on top of it:
const id = ts.factory.createIdentifier("x");
const stmt = ts.factory.createVariableStatement(
undefined,
ts.factory.createVariableDeclarationList(
[ts.factory.createVariableDeclaration("x", undefined, undefined, ts.factory.createNumericLiteral("1"))],
ts.NodeFlags.Const,
),
);
const printer = ts.createPrinter();
printer.printFile(ts.factory.updateSourceFile(sourceFile, [stmt]));
const result = ts.transform(sourceFile, [
(context) => (root) =>
ts.visitNode(root, (node) => {
// rewrite AST nodes here
return node;
}),
]);ts.visitNode, ts.visitNodes, ts.visitEachChild, and ts.visitIterationBody
are exported for traversal, along with the TransformerFactory<T>,
Transformer<T>, TransformationContext, and Visitor types. API.printNode
and ts.printNode provide printing of a single node with options.
Type checker
program.getTypeChecker() returns a TypeChecker (aliased Checker) with the
TS5 checker surface:
const checker = program.getTypeChecker();
checker.getTypeAtLocation(node);
checker.getSymbolAtLocation(node);
checker.getAliasedSymbol(symbol);
checker.getExportsOfModule(moduleSymbol);
checker.getPropertiesOfType(type);
checker.getApparentType(type);
checker.getBaseTypeOfLiteralType(type);
checker.getSignaturesOfType(type);
checker.getReturnTypeOfSignature(signature);
checker.getDeclaredTypeOfSymbol(symbol);
checker.getFullyQualifiedName(symbol);
checker.typeToString(type);
checker.symbolToString(symbol);
checker.signatureToString(signature);
checker.getConstantValue(node);
checker.getJsxIntrinsicTagNamesAt(pos);The Type, Symbol, Signature, TypePredicate, TypeParameter, and
Instantiation types are exported.
Module resolution
ts.resolveModuleName(moduleName, containingFile, compilerOptions, resolutionMode?);
ts.resolveModuleNameFromFile(moduleName, containingFile, compilerOptions, resolutionMode?);
ts.resolveTypeReferenceDirective(typeReferenceDirectiveName, containingFile, compilerOptions, resolutionMode?);resolveModuleName returns { resolvedFileName?, originalPath?, extension?, isExternalLibraryImport?, resolvedUsingTsExtension?, failedLookupLocation? },
while resolveModuleNameFromFile mirrors the TS5 ResolvedModuleWithFailedLookupLocations
shape ({ resolvedModule?, failedLookupLocations }).
resolveTypeReferenceDirective resolves /// <reference types="..." /> entries
and returns the TS5 ResolvedTypeReferenceDirectiveWithFailedLookupLocations
shape. ts.ModuleResolutionKind and the ResolvedModule /
ResolvedModuleWithFailedLookupLocations / ResolvedTypeReferenceDirective /
ModuleResolutionHost types are exported. The cache-based resolver internals
(resolveModuleNameFromCache, nodeModuleNameResolver, bundlerModuleNameResolver)
are not yet available — see the deferred list below.
Diagnostics
getPreEmitDiagnostics, getConfigFileParsingDiagnostics,
flattenDiagnosticMessageText, formatDiagnostics,
formatDiagnosticsWithColorAndContext, createCompilerDiagnostic, and
createFileDiagnostic are exported, along with the Diagnostic,
DiagnosticWithLocation, DiagnosticMessageChain,
DiagnosticRelatedInformation, and DiagnosticCategory types.
Emit
program.emit(), ts.transpileModule(), and ts.transpileDeclaration() are
available. transpileDeclaration mirrors the TS 5.5+ API for emitting a
.d.ts from a source file.
Syntax utilities and node guards
SyntaxKind, SyntaxFlags, NodeFlags, ModifierFlags, TokenFlags,
ScriptTarget, ScriptKind, ModuleKind, ModuleResolutionKind, and JsxEmit
are exported. The ast/is entry point exports the full predicate set
(isIdentifier, isClassDeclaration, isFunctionDeclaration,
isVariableDeclaration, isCallExpression, isPropertyAccessExpression,
isImportDeclaration, isExportDeclaration, isTypeAliasDeclaration,
isInterfaceDeclaration, isEnumDeclaration, isStringLiteral,
isNumericLiteral, …), and the same guards are re-exported from the default
API surface.
Language service
The LanguageService type is exported and a project-bound LanguageService
instance is available on projects opened through the API (it provides the TS5
surface: getQuickInfoAtPosition, getDefinitionAtPosition,
getTypeDefinitionAtPosition, getReferencesAtPosition,
getCompletionsAtPosition, getSemanticDiagnostics,
getSyntacticDiagnostics, getFormattingEditsForDocument, getRenameInfo,
findRenameLocations, getNavigationTree, and
getEncodedSemanticClassifications). The TS5 host-driven factory functions
(ts.createLanguageService(host), createLanguageServiceSourceFile,
createDocumentRegistry, and the LanguageServiceHost / DocumentRegistry
types) are not available yet — see the deferred list below.
Deferred items
The following TS5 entries need compiler-side infrastructure that the native port does not implement yet, so they are intentionally not exported:
- Watch/solution builders:
createWatchProgram,createWatchCompilerHost,createSolutionBuilder,createSolutionBuilderWithWatch. - Language-service host plumbing:
createLanguageService,createLanguageServiceSourceFile,createDocumentRegistry, and theLanguageServiceHost/DocumentRegistrytypes (the existingLanguageServiceis project-bound rather than host-driven). - Cache-based module-resolution internals:
resolveModuleNameFromCache,nodeModuleNameResolver, andbundlerModuleNameResolver(they require a realModuleResolutionCacheand a bundler resolution mode that the native resolver does not expose yet;resolveModuleName,resolveModuleNameFromFile, andresolveTypeReferenceDirectiveare fully supported). SyntaxFlags(obscure scanner enum with no TS7 counterpart).
This package is designed so that TS5/TS6 compiler-API consumers can switch to TS7 by changing their import:
-import * as ts from "typescript";
+import * as ts from "@nn140/typescript/sync";Known intentional differences:
- The API is async-first. The sync entry point hides the asynchrony with
generators, so
await ts.createProgram(...)works in both entry points. createCompilerHost'sgetSourceFile/writeFilereturnPromises even in the sync entry point.APIis a class instance, not a namespace of free functions. The TS5/TS6 free-function surface (createProgram,createSourceFile, …) is available on theAPIclass; the top-level exports in this package are the async/sync wrappers.
This repository is the source of the @nn140/typescript package. The compiler
is written in Go (tsc/), and the JS API lives in src/.
npx hereby build # build the native tsc binary and the JS API
npx hereby test:api # run the API testsThere are many ways to contribute to TypeScript.
- Submit bugs and help us verify fixes as they are checked in.
- Review the source code changes.
- Engage with other TypeScript users and developers on StackOverflow.
- Help each other in the TypeScript Community Discord.
- Join the #typescript discussion on Twitter.
- Contribute bug fixes.
This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.
Find others who are using TypeScript at our community page.
The native port of TypeScript is still in progress, and so is this fork's API. If you find gaps, please file an issue on the fork's issue tracker.