Skip to content
 
 

Repository files navigation

@nn140/typescript

CI npm version

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/typescript

Why TS7?

TS7 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.

Package exports

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.

Main export

import { version, versionMajorMinor } from "@nn140/typescript";

version;        // "7.3.0" — the published package version
versionMajorMinor; // "7.1" — matches the compiler (tsc --version)

Getting started (ts-node style)

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.

API reference

Top-level values

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 and the System interface

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 class

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.

TS5/TS6-compatible compiler API

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

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.

AST, checker, and emitter

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.

Full TS5 API surface

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.createIncrementalCompilerHost

BuilderProgram 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 the LanguageServiceHost / DocumentRegistry types (the existing LanguageService is project-bound rather than host-driven).
  • Cache-based module-resolution internals: resolveModuleNameFromCache, nodeModuleNameResolver, and bundlerModuleNameResolver (they require a real ModuleResolutionCache and a bundler resolution mode that the native resolver does not expose yet; resolveModuleName, resolveModuleNameFromFile, and resolveTypeReferenceDirective are fully supported).
  • SyntaxFlags (obscure scanner enum with no TS7 counterpart).

Compatibility with TypeScript 5/6

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's getSourceFile/writeFile return Promises even in the sync entry point.
  • API is a class instance, not a namespace of free functions. The TS5/TS6 free-function surface (createProgram, createSourceFile, …) is available on the API class; the top-level exports in this package are the async/sync wrappers.

Building from source

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 tests

Contribute

There are many ways to contribute to TypeScript.

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.

Documentation

Issues and Feedback

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.

About

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

Resources

Code of conduct

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages