Limitations
scriptc supports a subset of JavaScript, TypeScript, and the Node.js APIs.
This page is a reference for the remaining restrictions and for runtime behavior that differs from Node.js.
You don't need to read it front to back: run scriptc coverage on your program, and come here when a diagnostic or a behavior difference needs more context.
The Node.js compatibility reference lists support API by API.
Some entries mention checked values.
When the type of a value is only known at runtime, such as unknown, any, the result of JSON.parse, or a value passed through untyped JavaScript, scriptc stores it together with its runtime type and checks it when the program converts it back to a specific type.
Entries that say a value "retains identity through checked storage" mean the same object comes back out, rather than a copy.
Language and API restrictions
The following sections describe what compiles and what doesn't, area by area. They are not exhaustive; the compiler's diagnostics are the authority for a specific program.
Language features
- Error causes: Accessor constructor options are unsupported.
Subclasses may redeclare
causeasunknownorobject(for examplecause?: unknown), which defines the own property aftersuper()returns as Node does; redeclarations with other types, parameter properties, and accessors namedcauseare unsupported.Error,TypeError,RangeError, andSyntaxErrorotherwise accept{ cause }, including through inherited constructors. Reads, writes, deletion, and"cause" in errordistinguish an absent cause from an explicitly undefined cause. Constructor causes are non-enumerable; assignment to an absent cause creates an enumerable property. Property descriptors and checked-value aliases share the cause, including getters and setters installed after construction. - Class reflection:
JSON.stringifyandObject.keysrequire every declared field to have a representation that can pass through runtime-checked storage.JSON.stringifywrites Date fields as their ISO text and Map and Set fields as{}, as Node.js does, and refuses classes with RegExp or Promise fields withSC1090.Object.keysraises an error for classes with opaque fields such as native Maps. Class fields, inherited accessors, and added properties retain identity through untyped values. - Method values: Borrowing a class method onto an unrelated object is unsupported.
Detached methods that use
this, builtin method values, abstract declarations, unspecialized generic methods, and incompatible override signatures produce runtime errors or compilation diagnostics. Supported class methods can be stored and passed as unbound functions. A field call supplies its containing instance asthis;call,apply, andbindwork when the signature supports runtime-checked conversion. Extracted overrides retain the selected method, and receiver validation accepts the declaring class and its subclasses. - Loose equality: Object-to-primitive
==and!=comparisons are unsupported becausevalueOfandtoStringcan execute user code. Convert the object explicitly before comparing. Comparisons between represented primitives and primitive unions support number, string, boolean, and BigInt coercions, includingx == nullandx != null. - Resource disposal: Top-level and switch-clause
usingdeclarations, andAsyncDisposableStack, are unsupported. Block- and function-scopedusingandawait usingsupport compiled classes with zero-parameter disposal methods, object literals and otherDisposable- orAsyncDisposable-typed values, and supported FileHandle, timer, immediate, child-process, and readline handles. A class instance reached through aDisposable- orunknown-typed value throws an SC2020 error when its declaration runs; declare the variable with the class type. Arrayfor (using ... of ...)loops also compile.SuppressedErrorvalues exposeerrorandsuppressed;extends SuppressedErrorand castingunknowntoSuppressedErrorare unsupported (narrow withinstanceof).DisposableStacksupportsuse,adopt,defer,move,dispose,disposedand[Symbol.dispose], and works withusing;useaccepts class instances, object literals and otherDisposable-typed values, and refuses unions that include class instances (narrow the value first). Disposal runs in reverse order and raises Node'sSuppressedErrorchain when more than one callback throws. - Async iteration: Async
yield*delegation, stored Web or Node iterator handles, and general structural async-iterator objects are unsupported. Typed async generators support lazy execution,await, directyield, queued.next()/.return()/.throw()requests, andfor await.for awaitalso accepts NodeReadablestreams, WebReadableStreamvalues, and compiled class iterators whose zero-parameternext()returns a promise of a{ value, done? }record. A class instance whose[Symbol.asyncIterator]()returns an object literal, or that has only[Symbol.iterator](), iterates through the checked-dynamic async protocol, and an early exit awaits the iterator'sreturn(). Abrupt completion runs cleanup, including literaldestroyOnReturnandpreventCanceloptions. Thenode:timers/promisessetInterval(delay, value)iterator compiles without AbortSignal options.Array.fromAsyncaccepts arrays of values or of promises and typed async generators, with an optional mapping function; athisArgand arrays that mix values and promises are unsupported. - Iterable values: A value typed
Iterable<T>can hold an array, a Set, a Map (forIterable<[K, V]>), a string (forIterable<string>), a generator, or a Map, Set or array iterator. Class instances with their own[Symbol.iterator]method and typed arrays can't be stored in anIterable<T>and are reported at the conversion. - Generics: Generic functions declared inside other functions, generic class expressions, and generic methods requiring dynamic dispatch are unsupported. Generic classes can extend generic bases when each specialization has a concrete layout. Independent concrete uses have no specialization-count limit; recursively expanding demands and type layouts produce diagnostics. Other generic calls compile when the target resolves statically. Generic function values require a concrete signature at use and a binding that is never reassigned.
- Variadic wrappers: A generic higher-order wrapper is specialized to each wrapped function's exact signature.
Parameters<F>,ReturnType<F>, and rest parameters typed as fixed tuples become that signature's parameter list. A function expression with no parameters that readsargumentscompiles only when its value is asserted to, or contextually typed as, one fixed-arity signature;argumentsis then that signature's tuple. Forwarding it withfn.apply(this, arguments)passesthisthrough. Readingfn.nameon a wrapped function requires its name to be known where the wrapper is called, such as a function declaration or aconst-bound function.Parameters<F>over a signature with optional or array-typed rest parameters is unsupported, because that tuple has no fixed length. - Function values: Immutable aliases of overloaded program functions retain per-call overload resolution and identity.
A function stored in a slot with a different signature remains the same function for equality, array searches,
length, and own properties. Typed rest-parameter functions can be stored and called indirectly, including through a slot with fixed parameters, where the slot's arguments arrive in the rest array. Builtin function values have API-specific restrictions; see Builtin function values. - JavaScript parameters: In a JavaScript file TypeScript does not check, a prototype method (
C.prototype.m = function (...) {}) takes whatever values its callers pass; its JSDoc types document the usual values without constraining them. A sloppy-mode function with named parameters may readargumentsonly where the aliasing of its parameters cannot show: it readsarguments.length, or reads elements and never writes a parameter or an element. Other uses ofargumentsin such a function are refused withSC1090; ES modules,'use strict'code, classes, and functions with default, rest, or destructured parameters have no such restriction. A sloppy-mode function called withundefinedornullas its receiver gets the global object asthis, as in Node. Called with a primitive receiver, itsthisis the primitive itself, where Node passes the primitive's wrapper object (typeof thisis"object"there). - Argument spreads: Non-empty fixed tuples can spread into fixed signatures; arrays, Sets, and compiled class iterables can spread into typed rest parameters.
Runtime-length spreads into fixed or rest parameters require types that support checked
unknownconversion. Other JavaScript calls use the checked-value path; unsupported static forms produce a diagnostic. Calls with no native parameter slot are unsupported for runtime-length spreads. Arguments evaluate once, in source order, before defaults run, including surplus arguments. - Dynamic imports: Computed specifiers, import attributes, CommonJS namespace synthesis, and imports of shipped JavaScript packages are unsupported unless the target is a compiled ESM module.
Literal
import()of compiled ESM and TypeScript modules and of supported Node builtins compiles. Evaluation is lazy and microtask-delayed, top-levelawaitis honored, repeated imports share namespace identity, exported mutable bindings stay live, and namespace keys use Node's sorted order. - CommonJS
require: Literalrequire()calls of compiled modules, supported builtins, and JSON documents compile. Reading a top-levelconstorletrequire binding before itsrequireruns throws the sameReferenceErroras Node.js. Avarbinding that code above itsrequirecan reach is unsupported, and so is a read that compiles to no checkable expression, such as exporting the binding before therequire. JSON documents are parsed at build time, and everyrequire()of a document returns the same object. Destructuring the exports of a module supports plain and renamed properties, plus nested patterns for builtin sub-modules such asutil.types. Any pattern works on a JSON document. Defaults, rest elements, and nested patterns over other modules are unsupported. A require cycle compiles when each of its modules assigns all of its exports before its firstrequireand uses the other modules of the cycle only inside functions that its top-level code can't call. Other require cycles are rejected withSC1016. A top-levelreturnends the module's evaluation. It is unsupported when the module assigns exports after it, or when a function that exists before it runs reads a binding declared after it, such as a callback created above thereturnor a function declaration. - JSX: JSX in
.tsx,.jsxand JavaScript files compiles with the project'sjsxsetting:"react"withjsxFactory,jsxFragmentFactoryorreactNamespace, and"react-jsx"or"react-jsxdev"withjsxImportSource, as well as the@jsx,@jsxFrag,@jsxImportSourceand@jsxRuntimepragmas. The checker types JSX with these settings, and each element becomes the call TypeScript emits for it, importing the automatic runtime's functions from<jsxImportSource>/jsx-runtimeorjsx-dev-runtime."jsx": "preserve"and"react-native", which keep JSX in the output, are refused. The call an element becomes must type-check: a factory or runtime function whose parameters do not accept what an element passes is reported at the element. With"react-jsxdev",jsxDEVreceivesundefinedasselfwherethishas no declared type (in a function that is not a method), which is the value such a function observes when called without a receiver.
Types and class definitions
- BigInt: BigInt filesystem stats are unsupported.
Typed code cannot construct
BigInt64ArrayorBigUint64Array; JavaScript that names either one gets the checked-dynamic element kinds, where elements are BigInts. Arbitrary-precision BigInts otherwise support literals, operators, conversions, arrays, records, classes, closures, unions, promises, typed Map keys and Set elements, Buffer 64-bit reads/writes, and DataView 64-bit access. Nativeunknownand JavaScriptanystorage preserve BigInts, including checked Map keys and Set elements. JSON serialization throws aTypeErrorunless a replacer converts the value. - Interfaces: Interfaces explicitly implemented by compiled classes retain live object identity through checked native values.
Method-signature interfaces and callable-property interfaces structurally implemented by class methods use the same representation.
A call to a method signature of such an interface calls the class's method directly when the receiver is an instance of a compiled class, and a read of a property signature reads the class's field directly; object literals, accessors, and methods the program replaces on an instance or prototype use dynamic property lookup.
Arrays of such interface values are native arrays whose elements keep their identity; methods without a native form for them run on the array's dynamic view, which shares its elements.
Other data interfaces retain native record layouts and their copy-coercion rules.
Generic methods require a statically resolved body; a
constinterface binding initialized directly withnewcan keep the concrete class for specialization. Unsupported member representations produce diagnostics. - Record shapes: Records use exact native layouts.
Passing
{ a, b }where{ a }is expected can produceSC2002. Accepted flows into a strict field-subset shape copy the record; see Record identity and property order. - Unions: Narrow a union before an operation whose members require incompatible native representations, such as reading
u.lengthonstring | string[]. Some union-to-union widening and unions combining function and data members are unsupported. Same-representation methods on class unions,mapandforEachon array unions, and shared or joinable field reads compile.console.log(u)supports printing a whole union. A union may hold one promise beside other members, such asT | Promise<T>orPromise<R | void> | R | void:await, an async function'sreturn,Promise.resolve, andinstanceof Promiseact on the member it holds, with Node's microtask timing. A promise member beside a member that declaresthen, two promise members in one union, andconsole.logof a union holding a promise are unsupported. - Dynamic slots: A field, parameter, return value, variable or expression whose declared type has no native representation compiles as a checked dynamic slot instead of failing the build.
The parts of the type that compile keep their native layout, and only the failing parts hold checked-dynamic values.
Operations on those values run in the dynamic tier, and reading one into typed code checks it against the type that reads it, so a value that contradicts its declaration throws a
TypeErrorwhen typed code first uses it rather than when it is stored. Each slot is anSC6104warning;scriptc coverage --fail-on=dynamic-slotsfails on them, and--tier=static-onlyturns them back into build errors. Values that scriptc cannot produce at all, such asWeakRefinstances, still fail where they are created. - Null and optional values:
undefinedandnullcompile as standalone values and union members. Optional record and class fields and optional, default, and rest parameters also compile, including rest parameters typedunknown[]orany[], whose functions take any number of arguments. A function value whose fixed parameters are allunknownorany, or that has none, can be stored where such a variadic function type without fixed parameters is expected: each call passes the arguments in order,undefinedfor the ones the caller left out. Other function values with fixed parameters cannot be stored there. - Static field updates: Numeric static fields support
++and--through the declaring class or an immutable alias. Updates through a subclass name are unsupported because JavaScript creates a separate property on the subclass. - Array subclasses: A class that extends
Arraycompiles: its instances are arrays, andmap,filter,sliceand the other methods that create arrays return instances of the subclass, as in Node.js. A generic subclass (class Bag<T> extends Array<T>), a class that extends such a subclass, and a subclass that declaresSymbol.speciesare unsupported. A method whose result the subclass's constructor cannot construct throws aTypeError: the constructor's parameters must take the one length argument, and amapto another element type needs a constructor that adds no elements. - Local class expressions: Static fields and static blocks in TypeScript files, decorators, private brands, and generic members are unsupported.
Static methods read the enclosing function's bindings and are inherited by subclasses.
A named class expression's methods and static members can refer to the class by its name.
Supported expressions preserve fresh constructor identity and shared captures across constructors, methods, accessors, and arrow fields.
Local inheritance requires a compiled base class.
Constructors retain identity,
typeof,name, andlengththroughunknown; cast back to their exact type before construction. Construction and static-member access directly throughunknownare unsupported. - Constructor-function inheritance: Module-level JavaScript classes can extend compiled ordinary constructor functions.
Constructors that return replacement objects, spread
superarguments, and reflective static inheritance are unsupported. Supportedsupercalls preserve receiver and field initialization order and capture the base prototype at class evaluation. - Symbol fields: Instance fields require a stable module-level
Symbol()orSymbol.for()binding with a literal description or constant string binding. A[Symbol.toStringTag]field or getter with a string value sets the tag thatString(),Object.prototype.toStringandutil.inspectprint; fields keyed by other well-known symbols are unsupported. Reassigned keys, runtime-computed descriptions, distinct symbols with the same description in one class, and copying symbol fields with rest bindings orObject.assignare unsupported. JavaScript object spreads copy represented own symbol fields. Equal registry keys share a field across modules. Uninitialized JavaScript fields start asundefined; TypeScript fields require an initializer or unconditional constructor assignment. Represented symbol fields and methods, including inherited members, remain accessible through checked values.
Promise.all([work(1), work(2)]) infers a tuple.
Some tuple operations, such as .join(), are unsupported.
If you need array operations on the result, declare the input as an array:
Promise.allSettled and Promise.any take the same Promise<T>[] input and return PromiseSettledResult<T>[] and T.
Builtin APIs
A declaration in the standard library does not guarantee that an API compiles.
Unsupported declared APIs produce SC2020, with alternatives where available.
Check the Node.js compatibility reference for API-level support.
- Text encoding:
TextEncoderandTextDecodercan be stored in fields, arguments, return values, arrays, and closures. Encoding supports UTF-8, includingencodeIntointo a Uint8Array or Buffer view. Codec properties expose the canonical encoding and decoder flags. Codecs held inanyorunknownstorage keep their identity and streaming state, and dynamic code can callencode,encodeIntoanddecode, with options objects, and read their properties. Decoding accepts recognized WHATWG labels, including runtime labels and omitted or undefined encodings. Literal constructor options supportfatalandignoreBOM; literal decode options support streaming UTF-8, UTF-16, and single-byte encodings. Other legacy streaming encodings, runtime options objects, inspection, JSON conversion, and module-scope declarations usingvaror lacking an initializer are unsupported. Use initializedletorconstbindings for stored codecs. - EventEmitter: Literal event names use fixed argument tuples.
Number,
null,undefined, and boolean names register underString(name), as in Node. Computed string names with a constant prefix or suffix that excludeserror, meta events, and stream-internal events pass arguments of the exact arity with checked conversion. Other names reach an EventEmitter as through an untyped value: a name computed at run time converts withString(name), then the name is matched against the program's literal event names when the call runs. The name expression is evaluated before it converts; a name whose static type is a string or number literal is a compile-time key only when reading it runs no program code (a literal, anull,undefined,trueorfalsekeyword, a binding read, a stored field or record entry read), and a call or an accessor lowers as a run-time name. On streams, those names and names that may reach internal events are unsupported. Symbol names other thanevents.errorMonitorare unsupported. Once the program registers a listener under an unrestricted name, typedlisteners()/rawListeners()results are unsupported for events that literal names register with typed listeners. An emitter reached through an untyped value shares one listener list with its typed uses, so untyped registrations and emits reach typed listeners and typed emits reach untyped listeners. An untypedemitof an event that has a listener with typed parameters converts its arguments to the event's typed tuple before any listener runs, and throws aTypeErrorwhen they do not convert. Through an untyped value,listeners()andrawListeners()of an event with a listener that has typed parameters are unsupported, andemit('error')of an object that is not an Error with noerrorlistener is unsupported. AnewListenerorremoveListenerlistener registered through an untyped value receivesundefinedin place of a listener registered with typed parameters. A typederrororerrorMonitorlistener throws aTypeErrorwhen an emitted payload that is not an Error does not convert to its parameter. Reading EventEmitter methods as properties through an untyped value (typeof emitter.listeners) answersundefined.EventEmitter.prototype.<method>.call(receiver, ...)runs the method typed whenreceiveris statically an emitter instance; a receiver of typeanyruns the untyped method over its JavaScript_events, which does not reach a compiled emitter's listeners. The method is read fromEventEmitter.prototypeor from an emitter reached through a binding, a stored field, or a record entry; an accessor or a call on that path is unsupported, since skipping it would drop its effects.events.onceaccepts EventEmitter and stream instances with a literal event name and an optional object-literal{ signal }; a stream'sdataevent, other options values, and EventTarget emitters are unsupported. ReadingdefaultMaxListenersthrough a CommonJS destructured or member binding (const { defaultMaxListeners } = require("events")) is unsupported. - AsyncLocalStorage: timer, interval,
setImmediate,process.nextTickandqueueMicrotaskcallbacks run with the stores that were active when they were scheduled, as in Node. The completion callbacks offs,cryptoandzlibcallback APIs,dns.lookup,child_process.execFile,server.listen,net.connect,http.request,http.getanddgramrun with the stores that were active at the call, as in Node. Events ofnet,tls,httpandhttpssockets, servers, requests and responses run with the stores Node runs them with. A socket's or client request's events see the context of the call that created it, and a server's events and its requests' and responses' events see the context of itslisten()call. Socketwriteandendcallbacks,'finish'andserver.close(callback)see the context of their call. Stream events and callbacks run with the stores of the code that triggers them, as in Node. Stream steps that Node defers withprocess.nextTicksee the context that scheduled them, andstream.finishedandstream.pipelinecallbacks see the context of their call.fsread and write streams andzlibstreams run their events and callbacks in the context that created them. Events ofchild_processchildren, their standard streams and their IPC channels see the context of thespawn()orfork()call; stdin's'finish'andsend()callbacks see the context of their call. A clienthttp2session's events see the context of itshttp2.connect()call, and a client stream's events the context of itsrequest()call. Anhttp2server's'session'and'stream'events and the compatibility API's request handler see the context of itslisten()call; a server stream's own events, and its compatibility request's and response's, run with no store, as in Node.AsyncResourcehas no lowering yet. - Streams and readline: Stream chunks are Buffers or strings, and on an object-mode side any value that converts to a checked-dynamic value.
NodeJS.ReadableStreamandNodeJS.WritableStream, andstream.Readableandstream.Writableunder@types/node, accept every stream: when a program passes file, zlib, ornode:streamstreams through them, child-process pipes andprocess.stdoutandprocess.stderrjoin those streams asReadableandWritableinstances.readable.pipe(process.stdout)andreadable.pipe(process.stderr)compile and, as in Node, do not end the process stream. When an untyped value reachesNodeJS.ReadableStreamorNodeJS.WritableStream, those two interfaces hold any value, so JavaScript stream objects (constructor-function streams, plain objects withonandpipe) pass through TypeScript functions typed with them and come back to JavaScript as the same objects. Member calls on such a value use the native stream when it is one and call the object's own members otherwise;readable.pipe()into a JavaScript destination follows Node's pipe protocol. The firstpipelinestage may arrive as an untyped value that is a native stream, aCipherivorDecipherivvalue, or an iterable: a string, an array, a generator object, or any value with aSymbol.asyncIteratororSymbol.iteratormethod, which the pipeline pumps into the next stage as Node does. It may also be a source function, which the pipeline calls with{ signal }and whose iterable result it pumps, or a{ readable, writable }pair, whose readable side it pumps. Laterpipelinestages that arrive as untyped values may be native streams,CipherivandDecipherivvalues, functions, and iterables. A function is called with the previous stage and{ signal }as a function stage: before the last stage it must return an async iterable, and as the last stage it may return a promise, whose value resolves the pipeline, or an async iterable, which feeds the PassThrough thatpipeline()returns. An untyped source function, function stage, or destination that returns a stream is unsupported. An iterable becomesDuplex.fromof it, which the next stage reads from while the stages before it are not read, as in Node. A pipeline branches at run time on whether each of its first three untyped stages after the first is a function; a function in a later untyped stage, an untyped web stream, and a{ readable, writable }pair after the first stage throw a not-supported error.for awaitsources that arrive as untyped values must be native streams, orCipherivandDecipherivvalues, at run time; other values throw a not-supported error. Native streams expose noemitto JavaScript, so a JavaScript stream whose ownpipe()emits on its destination (the legacyStreampipe) cannot pipe into one.Readable.fromaccepts strings, Buffers, arrays, Sets, Maps, Map and Set iterators, generators, async generators, and class iterables and async iterables, and in JavaScript any iterable or async iterable. In JavaScript, a sync iterator value with athenmethod that is not a promise, and an object whose[Symbol.asyncIterator]or[Symbol.iterator]method is a generator method, are unsupported. TheobjectModeoption, and thereadableObjectModeandwritableObjectModeoptions of aDuplex,Transform, orPassThrough, taketrueorfalseliterals in an options object literal; options passed as a value are read when the stream is built. In typed code, awriteortransformcallback, or a_writeor_transformmethod, may declare its chunk with any type that converts to a checked-dynamic value: the chunk converts when the callback runs, and a value of another type throws a TypeError there. An object-mode write passes its encoding argument towriteandtransformas Node does (undefinedwhen absent,nullwhen a callback took its place); a parameter declaredstringreceives""forundefinedandnull, and one declaredstring | null | undefinedreceives Node's value.readable.read()on an object-mode stream answers any value it holds.node:stream/consumersand readline interfaces read object-mode streams of strings and Buffers; other values throw a not-supported error.pipelineaccepts function stages anywhere among its streams: async generator functions (async function* (source), iteratingsourcewithfor await), an async generator source function (async function* ({ signal })), an async generator function as the destination, and an async function destination whose value resolves the promise form and reaches the callback's second argument. A stage is written inline, or named by a function declaration or aconstbound to a function expression that nothing reassigns. The source may also be an array, a string, aSet, aMap, a generator or async generator object, or a synchronous generator function without parameters; their elements reach the next stage on the same ticks as in Node. Stages may take the{ signal }argument. With a function destination,pipeline()returns an object-mode PassThrough that receives an async generator destination's values, or an async function destination's value unless it isnullorundefined.@types/nodetypes that result asNodeJS.WritableStream, sofor awaitover it needs thePassThroughtype (pipeline(...) as PassThrough, or a JSDoc@type). In typed code, a pipeline callback with an async function or async generator destination receivesnullfor no error when its error parameter cannot holdundefined(@types/node declares itNodeJS.ErrnoException | null), andundefinedwhen it can, as in Node.Readable.fromacceptsobjectModeandhighWaterMarkoptions. TheReadableoperators (map,filter,forEach,toArray,some,find,every,flatMap,drop,take, andreduce) acceptconcurrency,highWaterMark, andsignaloptions. Their callbacks may take the{ signal }argument,mapmay return any value, andflatMapmay return any iterable, async iterable, or stream.Duplex.fromaccepts an async generator function, which reads what is written to the Duplex, aDuplex,TransformorPassThrough, which it returns, and the valuesReadable.fromaccepts, which give a Duplex that is not writable. It also accepts a loneReadableorWritableand a{ readable, writable }pair, which the Duplex reads and writes through, a promise, whose value it reads, and an async function, which reads what is written and must resolve tonullorundefined. ADuplex.frombody function may take the{ signal }argument, which is aborted with the error the Duplex is destroyed with.stream.composeaccepts streams and async generator functions in any position, an async function as the last stage, and an array, a string, or a generator as the first stage; one stage isDuplex.fromof it. A webReadableStreamis read as an async iterable byReadable.fromand as the first stage ofcomposeorpipeline, and through its reader byReadable.fromWeb(withobjectMode,highWaterMark,encoding, andsignalin an options object literal) andDuplex.from. In TypeScript,new TransformStream()without arguments builds the identity transform: its readable side is a webReadableStream, its writable side supportsgetWriter,abort,close, andlocked, and the writer supportswrite,close,abort,releaseLock,ready,closed, anddesiredSize, with Node's backpressure (a write completes when the readable side reads its chunk). In TypeScript,tee,pipeTo, andpipeThrough, theWritableStreamconstructor with an underlying sink, and aTransformStreamwith a transformer or queuing strategies compile: a program that uses one of them builds itsReadableStream,WritableStream, andTransformStreamvalues with the same classes as JavaScript, and aResponseorRequestbody has those members too. A TypeScript program that uses onlygetReader,cancel,locked, and the identityTransformStreamkeeps the smaller native streams. A web stream in a later compose stage andReadable.toWebare unsupported. TheERR_INVALID_ARG_VALUEmessage for a stream that is no longer readable or writable names the stream's class instead of printing the stream.readable.compose(stage, { signal })isstream.compose(readable, stage)with the signal added; the options are an object literal whosesignalis a variable or a property read.pipelinefromnode:stream/promisesaccepts a trailing{ signal, end }object, with or without function stages, andfinishedacceptsreadable,writable,error,cleanup, andsignaloptions, with boolean literals for the flags. Stream constructors accept asignaloption in an options object literal, andstream.addAbortSignalaccepts any stream. Theconstructoption and_constructmethod,decodeStrings, anddefaultEncodingwork on every stream class, and thewritevoption and_writevmethod on every class with a writable side. AdecodeStringsordefaultEncodingvalue known only at run time is unsupported after an option member whose value has effects (a call or an assignment). In typed code, awriteventry'sencodingdeclared as a string receives""where Node passesundefinedornull(an object-mode write).setDefaultEncoding()takes any encoding Node knows.node:readlineandnode:readline/promises(also reached asreadline.promises) interfaces, fromcreateInterface(options)orcreateInterface(input, output, completer, terminal), readprocess.stdinor a readable stream:question,prompt,write(with a key object literal ofname,ctrl,meta, andshift),pause,resume,'line'/'close'/'pause'/'resume'/'error'/'history'/'SIGINT'/'SIGTSTP'/'SIGCONT'listeners, andfor awaitcompile.on,once, andaddListenerreturn the interface, so registrations chain. Thehistory,historySize,removeHistoryDuplicates,completer,tabSize, andescapeCodeTimeoutoptions are validated as in Node. Withterminal: true, or with noterminaloption andprocess.stdoutas the output when it is a TTY, the interface runs Node's terminal mode: the editing keys, the kill ring, undo and redo, history recording and recall, Tab completion through the completer, Ctrl+C, Ctrl+D, and Ctrl+Z,TERM=dumb, and the same escape sequences written to the output. The output's'resize'event does not redraw the line. The cursor never stops between the two UTF-16 units of a supplementary character: where Node's Up or Down movement through a multiline line would, the cursor moves to the character's start or end. In JavaScript, a'history'listener receives a copy of the history; its changes are written back when the listener returns, but the copy is notrl.historyitself.rl.history,historySize,historyIndex,crlfDelay,tabSize,escapeCodeTimeout,line,cursor, andterminalread as in Node;rl.cursorisundefinedon an interface that is not a terminal.rl[Symbol.dispose]()closes the interface, andinstanceofwithreadline.InterfaceorreadlinePromises.Interfaceanswers whether the interface came from that module, as in Node. In JavaScript, the input and output can be any expression that evaluates to a stream, such as a function's result or an object's member; a value that is not a stream is unsupported. In JavaScript,question()andsetPrompt()accept a value that is not a string: when such a prompt is written, an interface that is not a terminal throwsERR_INVALID_ARG_TYPEas Node does (thereadline/promisesquestion rejects with it) and the question stays pending, and a terminal interface writesString(value). A terminal interface's prompt that is an object or a symbol,getPrompt()while the prompt is not a string, andgetCursorPos()with an object or symbol prompt are unsupported.readline.cursorTo,moveCursor,clearLine, andclearScreenDownwrite toprocess.stdout,process.stderr, a writable stream, or nothing fornullandundefined; their callbacks take no parameters. Thereadline/promisesReadlineclass writes to the same outputs.readline.emitKeypressEventsemits'keypress'events onprocess.stdinor a readable stream, shared with terminal interfaces on that stream as in Node; a listener's first parameter must admitundefined, which it receives for escape sequences. Chained listener registration is unsupported.node:stream/webexports the same classes as the globals; in TypeScript,ReadableStream,WritableStream, andTransformStreamhave lowerings. In JavaScript,ReadableStream,WritableStream, andTransformStreamwith their default readers, writers, and controllers,CountQueuingStrategy,ByteLengthQueuingStrategy,TextEncoderStream, andTextDecoderStream, as globals and asnode:stream/webexports, are constructor values with Node's prototypes, brand checks, and errors. Their underlying sources, sinks, and transformers, queuing strategies with asizefunction, readers and writers,tee,pipeToandpipeThroughwith their options and an abort signal,ReadableStream.from, and async iteration settle promises in Node's order, and the streams take own properties.TextDecoderStreamdecodes UTF-8; its other encodings are unsupported. A JavaScriptReadableStreamgiven as aResponseorRequestbody, or asfetch's body, is read through a stream of its own:response.bodyis that stream rather than the one passed in, and the stream passed in is locked from the start. In JavaScript, aResponseorRequestbody has the members of aReadableStream, includingtee,pipeTo,pipeThrough,values, andfor await, and its lock andbodyUsedfollow them. After one of those members is used, a body given to a newResponseorRequestis locked from the start, as a JavaScriptReadableStreamis. In a program that names none of the web stream classes, those members are available when the program's JavaScript names one of them or iterates a body withfor await; reached only through a computed key, they are not. In JavaScript, a byte stream (type: 'bytes'), a BYOB reader, a class that extends one of these classes,Object.getPrototypeOfon these values, their use asWeakMapandWeakSetkeys, andReadableStream.fromof a function that is not iterable are unsupported. - CommonJS metadata: The module graph is fixed at build time.
Cache deletion or reloading, metadata writes,
module.pathsmutation, andrequire.extensionsare unsupported. Read-only access tomodule.id,filename,path,paths,loaded,isPreloading,parent,children,require.main, andrequire.cachelookup/enumeration compiles. - ESM metadata: Native
import.meta.url,filename,dirname, andmainsupport dot access, statically known keys, and destructuring selected fields. Storing or mutating the metadata object, rest bindings, runtime keys, and storedresolvecallbacks are unsupported. Nativeimport.meta.resolve()requires a literal specifier. Module instances distinguished by URL query strings or fragments are unsupported. - Date: Spread constructor arguments,
toLocaleDateString(), and locale or options arguments to the locale formatters are unsupported. Dates are objects with identity:===and==compare identity,new Date(date)makes a new Date, setters change the one Date every reference holds, and Dates compile in arrays (includes,indexOf,lastIndexOf,join, and defaultsortbytoString()text), in unions with other types, as Map and Set keys and values, and in records, tuples, class fields, closures, promises and generators. Thrown and rejected Dates keep their identity;structuredCloneandpostMessagecopy them. Zero-argument, single number/string, and local-time year/month field constructors,getTime,valueOf,toISOString,toUTCString,toJSON(astring | null: null for an invalid date, as in Node),toString,toDateString,toTimeString, the argument-freetoLocaleString()andtoLocaleTimeString()(the default locale's ICU patterns over the host time zone, as Node prints them), the local and UTC calendar getters and setters,setTime,getTimezoneOffset, and single-stringDate.parsecompile. Unary+,-andNumber(date)read the time value;String(date), template literals and+with a string read thetoString()text;date[Symbol.toPrimitive](hint)compiles with a literal hint. A Date converted tounknownis the same Date object. See Dates and timezones for timezone data. - URL: Absolute inputs and relative inputs with runtime string or URL bases, including optional bases, compile.
URL.canParse,URL.parse,toString(), andtoJSON()compile; the factories use the same parser as construction, returningfalseornullfor rejected inputs while preserving conversion errors.href,protocol,username,password,host,hostname,port,pathname,search, andhashsupport assignment in native code. Invalid component writes are ignored except for invalidhrefvalues, which throw; credentials are percent-encoded and ports accept valid leading digits. Native URL assignments require statically known property keys;+=accepts primitive operands, while other assignment operators and object operands for+=are refused.originis read-only.searchParamsis a live view whose identity survives query and URL replacement. - Legacy URL API:
url.parse(),url.format(),url.resolve(),url.domainToASCII(), andurl.domainToUnicode()compile, including Punycode hostnames and theDEP0169/DEP0170warnings. A parsedUrlobject supports reads, writes, and itsformat()method; itsparse(),resolve(),resolveObject(), andparseHost()methods throwSC2020, andurl.Urlandurl.resolveObject()are unsupported.ERR_INVALID_URLerrors have noinputproperty. - Deprecated
punycodeandconstantsmodules:punycode.encode(),decode(),toASCII(),toUnicode(),ucs2.decode(),ucs2.encode(), andversioncompile, with theDEP0040warning Node.js reports when the module loads. Arequire("punycode")made from insidenode_modulesdoesn't warn; arequire()used inside a larger expression, such asrequire("punycode").toASCII(name), doesn't warn either. Thepunycode.ucs2object itself is unsupported as a value. Theconstantsmodule is the frozen object Node.js builds fromos.constantsandfs.constants, plus thecrypto.constantsof Node.js 24.22.0. - Filesystem flags:
fs.openSyncsupports inline bitwise OR expressions ofO_RDONLY,O_WRONLY,O_RDWR,O_CREAT,O_EXCL,O_NOFOLLOW,O_NONBLOCK,O_TRUNC, andO_APPEND, with an optional creation mode. Computed numeric flags are unsupported because bit values vary by target.fstatSync,fchmodSync,fsyncSync, andlinkSyncsupport direct calls. On Windows, numeric opens withO_NOFOLLOWand calls tofchmodSyncthrowENOSYS; use a POSIX target if you require these operations. - Filesystem URL paths:
fsandfs.promisesfunctions acceptfile:URL paths and convert them asfileURLToPathdoes;existsSyncanswersfalseand thefs.promisesfunctions reject for a URL that does not convert. A URL path with options that are not literals is refused where Node checks those options before it converts the URL, except areadFileSyncencoding.fs.promisesfunctions also refuse a string path before a URL path; passfileURLToPath(url)instead. - Copy:
fs.cpSync,fs.cp, andfs/promisescpsupport every option and follow Node's two implementations:cpSyncreports the native binding's errors, and the callback and promise forms reportSystemErrors. Files, directories, and symbolic links are copied in directory order, as in Node. The callback and promise forms complete the copy before the callback runs or the promise settles. An asyncfiltermust return a promise that is already settled; a pending one throwsSC2020. On Windows, the three functions throwSC2020. - Glob:
fs.globSync,fs.globandfs/promisesglobsupport every option.withFileTypesmust be a literaltrueorfalse, andexcludefunctions cannot be combined withwithFileTypes. Thefs/promisesiterator is supported only as the source of afor awaitloop, and its walk completes when the loop starts.fs.globcallbacks receive file names, not Dirents. - FileHandle and descriptor I/O: Static reads and writes accept Buffer and Uint8Array windows, numeric positions, and UTF-8 strings.
FileHandle reads also accept options records and allocate a buffer when omitted.
Vector I/O, truncation, syncing, and permission changes compile.
Ownership changes, timestamps, and bigint Stats remain unsupported; FileHandle streams and
readLinesare covered under File streams. Dynamic descriptor I/O accepts other ArrayBuffer views and Buffer encodings; read positions outside the safe integer range are refused. File operations complete synchronously before their callbacks or promise continuations. Descriptor permission changes on Windows throwENOSYS. - File streams:
fs.createReadStream,fs.createWriteStream,new fs.ReadStreamandnew fs.WriteStream(in JavaScript sources), and FileHandlecreateReadStream,createWriteStreamandreadLinesreturn Readable and Writable streams. Options are checked when the stream is created, with Node's errors and order;flagsandmodeare checked when the file opens, so their errors arrive as'error'events.bytesRead,bytesWritten,path,pending,close(),close(callback)with a() => voidcallback, and the'open'and'ready'events compile. Numericflags, thefs,signalandwindowsHandleoptions, write streams with an encoding other than UTF-8, andinstanceof fs.ReadStreamorfs.WriteStreamare unsupported. - File watching:
fs.watchreturns anFSWatcherwhoseon,once,off, andclosetakechange,rename,error, andcloselisteners. A listener may take the event name and the entry name, but the name arrives as a string (Node's default encoding), so a listener annotated with theBufferarm of@types/node'schangeoverload has no lowering. Watching a directory on macOS with a listener that reads the entry name is refused withSC2020because FSEvents is not implemented yet; file watches and listeners that ignore the name work on every target. - Stat polling:
fs.watchFilepolls the resolved path everyintervalmilliseconds (default 5007) and calls its listener with(current, previous)Stats;fs.unwatchFileremoves the last listener registered with that callback, or every listener when called without one. The call must be a statement of its own, because theStatWatcherit returns in Node.js is not lowered, andbigint: trueis refused. - Crypto: Hashing, HMAC, PBKDF2, and HKDF support every digest
crypto.getHashes()lists in Node 24, with OpenSSL's aliases and object identifiers. Hash and Hmac accept every Buffer encoding and any TypedArray or DataView,createHashandhash.copytakeoutputLength, andcrypto.hashtakes its options object; HMAC, PBKDF2, and HKDF reject the SHAKE and KMAC digests with Node's errors. Hash and Hmac values are also Transforms: they can be written, piped into, used aspipeline()stages, read, and listened to, and they report Node's errors after the stream flushes.copy()of a Hash whose stream flushed, and stream use of a value after its stream closed, throw a coded SC2020 error. Throughunknownandanyslots and untyped JavaScript, Hash and Hmac values keep their identity and supportupdate(),digest(), and Hash'scopy(), called or read as values; their stream and event members there throw a coded SC2020 error.timingSafeEqualcompares any view or ArrayBuffer. Secret KeyObjects (createSecretKey,generateKeyandgenerateKeySyncforhmacandaes) supporttype,symmetricKeySize,export(),equals(), andinstanceof KeyObject, and createHmac, hkdf, createCipheriv, and createDecipheriv accept them;KeyObject.from()andtoCryptoKey()are not available.randomFill,randomFillSync(every view kind and ArrayBuffer),randomInt,randomUUID, andrandomUUIDv7follow Node 24.22, including callback timing; arandomIntcallback whose error parameter is typedError | nullreceivesnullwhere Node passesundefined. Scrypt supports its default parameters, numeric options, aliases, and memory limit. Both KDFs accept strings, Buffers, numeric typed arrays, DataViews, and fixed-length ArrayBuffers.createCipherivandcreateDecipherivsupport aes-128, aes-192, and aes-256 in CBC, CTR, GCM, CCM, ECB, CFB, CFB8, CFB1, and OFB modes and as key wrap (the wrap and wrap-pad ciphers and their -inv forms), des-ede3 in CBC, ECB, CFB, CFB8, CFB1, and OFB modes, des-ede in CBC, ECB, CFB, and OFB modes, chacha20, and chacha20-poly1305, on native targets, throughupdate(),final(),setAAD(),setAutoPadding(),getAuthTag(), andsetAuthTag(); other ciphers and wasm32-wasi builds are refused.getCipherInfoanswers Node's info for every cipher OpenSSL names, including the ones without a native implementation.getCipherInfooptions whose class defineskeyLengthorivLengththrow a coded SC2020 error. The result is Node's object; the SIV ciphers and the SM4 GCM, CCM, and XTS ciphers have nonid, and reading it where the declaredCipherInfotype givesnumberthrows a TypeError. Cipheriv and Decipheriv values are also Transforms: they can be written, piped into, used aspipeline()stages, read, iterated withfor await, and listened to, and their stream properties read as in Node; written chunks go throughupdate(), and the end pushesfinal()or reports its error through'error'. Throughunknownandanyslots and untyped JavaScript, in a program that uses streams, their stream properties and theiron,once,off,pipe,unpipe,read,pause,resume,setEncoding,write,end,destroy,cork, anduncorkmembers work;writeandendtake no encoding or callback there, and the other stream members throw a coded SC2020 error. Hash, Hmac, Cipheriv, and Decipheriv streams count a written string's bytes inwritableLength, where Node counts the string's length. Decrypting chacha20-poly1305 without an authentication tag fails infinal(); Node 24.22 returns unverified plaintext. Afterupdate()fails, for example past the AES-GCM limit of 2^36 - 32 bytes per message, every later call on that cipher throws; Node still letsfinal()run. An output encoding that is a function or an instance of a class definingtoStringthrows a coded SC2020 error.createECDHandECDH.convertKeysupport prime192v1, secp224r1, prime256v1, secp384r1, secp521r1, secp192k1, secp224k1, secp256k1, brainpoolP256r1, brainpoolP384r1, and brainpoolP512r1, on native targets, throughgenerateKeys(),computeSecret(),getPublicKey(),getPrivateKey(),setPrivateKey(), andsetPublicKey(), in compressed, uncompressed, and hybrid forms; the other curvescrypto.getCurves()lists and wasm32-wasi builds are refused. A call on an ECDH value whose arguments no @types/node overload accepts (getPublicKey("HEX")) is refused at compile time, as iscomputeSecret(view, encoding): Node reads that encoding as the input encoding and answers a Buffer where @types/node declares a string. ECDH property reads and writes throw a coded SC2020 error.createDiffieHellman,getDiffieHellman, andcreateDiffieHellmanGroupsupport the modp1, modp2, modp5, and modp14 through modp18 groups, explicit primes and generators, and generated safe primes, on native targets, throughgenerateKeys(),computeSecret(),getPrime(),getGenerator(),getPublicKey(),getPrivateKey(),setPublicKey(),setPrivateKey(), andverifyError, with Node's private key lengths, DH_check results, and errors; wasm32-wasi builds are refused. Primes longer than 8192 bits throw a coded SC2020 error; Node accepts primes up to 10000 bits for key generation and secrets.setPublicKey()andsetPrivateKey()keys longer than 80000 bytes, not counting leading zero bytes, throw a coded SC2020 error, as does a generator that long with a prime below 512 bits; Node accepts them. A call on a DiffieHellman value whose arguments no @types/node overload accepts, or whose output encoding is typedany, is refused at compile time, as are itsObject.prototypemethods; other property reads, and property writes, throw a coded SC2020 error.Object.keys()andindo not see a DiffieHellman's ownverifyErrorproperty, andJSON.stringify()andinstanceofare refused. AftercreateDiffieHellman(primeLength)throwsInvalid DH parameters, the next OpenSSL error Node throws can list the failed generation's errors inopensslErrorStack; errors in a compiled binary list only their own.crypto.diffieHellmancomputes ECDH and X25519 secrets from EC and X25519 keys, given as KeyObjects or in any formcreatePrivateKeyandcreatePublicKeyread, with Node's errors; DH keys have no KeyObjects here, and theDiffieHellmanandDiffieHellmanGroupconstructors are not available.checkPrime,checkPrimeSync,generatePrime, andgeneratePrimeSyncsupport bigint, ArrayBuffer, typed-array, Buffer, and DataView values and thechecks,safe,add,rem, andbigintoptions on native targets, with Node's errors; the callback forms compute before they return and call back in a later macrotask. Candidates and sizes longer than 262144 bits throw a coded SC2020 error, and wasm32-wasi builds are refused. Node calls their callbacks withundefinedas the error, which a callback whose error parameter is typedError | null, as @types/node declares it, receives asnull. RSA, RSA-PSS, EC, Ed25519, and X25519 private and public KeyObjects come fromgenerateKeyPairSync,generateKeyPair,createPrivateKey, andcreatePublicKey, on native targets.generateKeyPairSyncandgenerateKeyPaircheck their arguments in Node's order, with Node's errors, including the OpenSSL errors for RSA modulus lengths below 512 or above 2147483647 bits and for public exponents of 0, 1, or an even number, whichgenerateKeyPairpasses to its callback. RSA keys generate with modulus lengths from 512 to 8192 bits, an odd length from 2048 bits yielding one bit less as in Node, and odd public exponents up to 4294967295; longer moduli that Node accepts, andparamEncoding: 'explicit', throw a coded SC2020 error. The EC curves are prime256v1 (P-256), secp384r1 (P-384), secp521r1 (P-521), and secp256k1. Keys read and write PEM and DER as PKCS#1, SEC1, PKCS#8, and SubjectPublicKeyInfo, and JWK (Ed25519 and X25519 keys use PKCS#8, SubjectPublicKeyInfo, and JWK);createPublicKeyalso takes a private key or an X.509 certificate. EC, Ed25519, and X25519 keys also read and write theraw-publicandraw-privateformats, including compressed EC points. Raw X448, Ed448, and post-quantum keys, EC scalars of 0 or at least the curve order, and the EC point at infinity, which Node accepts, throw a coded SC2020 error. They supporttype,asymmetricKeyType,asymmetricKeyDetails,export(),equals(), andinstanceof KeyObject.crypto.sign,crypto.verify,createSign, andcreateVerifysupport RSA PKCS#1 v1.5 and PSS padding and ECDSA with DER and IEEE P1363 encodings over SHA-1 and SHA-2 digests, and Ed25519 throughcrypto.signandcrypto.verifywith anullorundefinedalgorithm. RSA-PSS keys follow their RSASSA-PSS-params as Node does: PSS padding only, the key's digest and MGF1 digest, and salts of at least the key's length, with OpenSSL's errors; their details name the parameters, they export as PKCS#8 and SubjectPublicKeyInfo only, and digests other than SHA-1 and SHA-2 in their options throw a coded SC2020 error. Ed25519 signing, verification, and private keys link when a string literal in the program namesed25519(in any case); without one they throw a coded SC2020 error, while Ed25519 public keys still import and export. X509Certificate supportspublicKey,verify(),checkIssued(),checkPrivateKey(),checkHost(),checkEmail(),checkIP(),toLegacyObject(),toString(), andtoJSON(), andString(), template literals, and+give its PEM text astoString()does.publicKey,verify(), andcheckPrivateKey()are refused in wasm32-wasi builds, and an Ed25519 certificate'sverify()needs theed25519literal like the other Ed25519 operations. Own-key walks over a certificate (Object.keys(),Object.entries(), spread,for...in, andhasOwnProperty) are refused, since Node keeps its fields as prototype getters.JSON.stringify()andconsole.log()of a certificate, a certificate stored in anunknownoranyslot, and its methods on a union-typed value are also refused. Sign and Verify values accumulateupdate()data and are not writable streams. Private keys export encrypted (cipher,passphrase) with aes-128, aes-192, and aes-256 in CBC and ECB modes and with des-ede3-cbc, PKCS#8 as PBES2 with PBKDF2-HMAC-SHA256 and PKCS#1 and SEC1 as traditional PEM, and the ciphers OpenSSL refuses for a form throw its errors; a cipher option can also be an OID; other ciphers Node encrypts with throw a coded SC2020 error. Encrypted private keys import with apassphrasefrom PBES2 with HMAC-SHA PRFs and the CBC and ECB ciphers, and from traditional PEM with the CBC ciphers, with Node's errors for a missing or wrong passphrase; other schemes and ciphers throw a coded SC2020 error once a passphrase is given. The other key types (dsa,ed448,x448, and the rest) and wasm32-wasi builds throw a coded SC2020 error or are refused. Comparing keys of different types withequals()answers false; Node also leaves an OpenSSL error queued, which a later key operation can report.publicEncrypt/privateDecryptremain unsupported. The WebCryptocryptoglobal, which node:crypto also exports aswebcrypto, supportsrandomUUID()andgetRandomValues(), also read as values from untyped JavaScript. Itssubtleobject, also node:crypto'ssubtleexport, supportsgenerateKey()andexportKey()for HMAC and AES keys,importKey()for HMAC, AES, PBKDF2, and HKDF keys,encrypt()anddecrypt()with AES-GCM, AES-CBC, and AES-CTR andwrapKey()andunwrapKey()of secret keys with AES-KW or those ciphers on native targets,deriveBits()andderiveKey()with PBKDF2 and HKDF, HMACsign()andverify(), and SHA-1 and SHA-2digest(). Secret keys import and export in theraw,raw-secret, andjwkformats.generateKey(),importKey(),exportKey(),sign(), andverify()also support ECDSA (P-256, P-384, and P-521), Ed25519, RSASSA-PKCS1-v1_5, and RSA-PSS, with thespki,pkcs8, andjwkformats andrawfor ECDSA and Ed25519 public keys; ECDSA, Ed25519, and RSA are refused in wasm32-wasi builds. ECDSA, Ed25519, and RSA link when a string literal in the program names the algorithm; a name built only at run time throws a coded SC2020 error.wrapKey()andunwrapKey()of ECDSA, Ed25519, and RSA keys throw a coded SC2020 error. Other SubtleCrypto methods, algorithms, and key formats are refused or throw a coded SC2020 error. Native derivations finish before their deferred callbacks, so computation blocks the caller. - Assertions: Assertion failures throw
assert.AssertionErrorwith Node'smessage,generatedMessage,code,actual,expected,operator, anddiffproperties.new AssertionError(options),instanceof, andassert.throws(fn, AssertionError)compile. WhenstrictEqualcompares function values,actualandexpectedread asundefined; whenassert.throwsorassert.rejectsreports an error that is not an instance of the expected class, or that does not match an expected object,expectedreads asundefined. Values whose type can be cyclic, such as recursive records, also read asundefined.assert.AssertionErrorused as a value outsideinstanceofthrowsSC2020. The comparison methods,ok,failandifErrorare function values that assert as the methods do; called through a stored value,okwithout a message reportsvalue == true, where Node quotes the call, andfailtakes at most one argument.throws,rejects,doesNotThrow,doesNotReject,matchanddoesNotMatchas values throwSC2020.strictEqualandnotStrictEqualcompare a number, string or boolean that can benullorundefined, such aschild.signalCode, with any number, string, boolean,nullorundefined.notStrictEqualof another value that can benullorundefined, such aschild.stdin, againstnullorundefinedcompiles;strictEqualof one throwsSC2020.assert.deepEqualandassert.notDeepEqualfollow Node's loose comparison, including Maps, Sets, Dates, regular expressions, typed arrays, and errors; operands whose type can be cyclic or holds functions inside a structure are refused.assert.partialDeepStrictEqualfollows Node's partial comparison over the same values, with the same refusals. Checked-dynamic values compared deeply have no cycle detection. Errors in failure messages print as[Name: message], where Node prints the stack when only one side is an error.new Assert(options)compiles when it initializes aconstwith literaldiff,strictandskipPrototypeoptions, or none, and the binding is only used to call assertion methods. Other instances, such as ones passed as values, destructured, bound withlet, or built from options that are not a literal, throwSC2020. WithskipPrototype,deepStrictEqualandnotDeepStrictEqualcompare class instances, and operands of different static types, as checked-dynamic values. - Concurrent tests: with
{ concurrency }above 1, subtests run on their own fibers, and results are reported in declaration order, as in Node. Concurrent bodies resume in Node's order aroundbeforeEachhooks and nested suites. Other runner steps, such asafterEachandafterhooks, take no microtask turns between bodies, so code that observes the interleaving of concurrent bodies across those steps can see a different order than Node. - Snapshots:
t.assert.snapshotandt.assert.fileSnapshotcompile, with Node's default serializer,JSON.stringify(value, null, 2), or anoptions.serializersarray literal. A compiled test reads the snapshot file Node writes beside the entry file,<entry file>.snapshot, at the entry file's path when the program was compiled. Running the binary with Node's flag--test-update-snapshotsas its first argument writes the snapshot files instead; as in Node, the flag is kept out ofprocess.argvand appears inprocess.execArgv. Snapshot files are read in the form Node writes them,exports[`key`] = `value`;statements. Thesnapshot.setDefaultSnapshotSerializersandsnapshot.setResolveSnapshotPathmodule functions throwSC2020. - TestContext values:
t.filePathis the entry file's path when the program was compiled.t.attemptis0, since a test runs once.t.passedisfalsewhile the body runs and the test's outcome in itsafterEachandt.afterhooks.t.workerIdisNumber(process.env.NODE_TEST_WORKER_ID) || undefined, as in Node.t.tagsis[], since thetagstest option throwsSC2020; the array is not frozen as Node's is. - Suite and hook contexts: a
describebody may take itsSuiteContext, which hasname,fullName,filePath,attempt,passedanddiagnostic. Hooks may take their context, as in Node: the suite's forbeforeandafter, the test's forbeforeEach,afterEach,t.beforeandt.after. TheSuiteContextsignalandlogmembers, and hookdonecallbacks, throwSC2020. - Module-level hooks:
beforehooks outside any suite run at theirbefore()call, and the first top-level test waits for the async ones;afterhooks outside any suite run after the last top-level test. Both get the root's context, named<root>. As in Node, a throwing rootbeforefails each top-level test with its error, without running its body, and cancels the tests and suites inside each top-level suite. A throwing rootafterreports the entry file as a failed result, and the exit code is unchanged. - Timeouts: when a test's
{ timeout }elapses, its running subtests are cancelled, as in Node. Subtests do not take their parent'stimeoutas their own, where Node's do, and the subtests of a timed-out test with{ concurrency }above 1 run to completion before the test reports. A body that keeps running after its timeout and callst.testagain runs that subtest, where Node reports it as not started. - Thrown values: a test that throws a value that is not an
Errorreports it in the failing section asutil.inspectrenders it, as Node does, for strings, numbers, booleans, objects, arrays,nullandundefined. A thrown class instance that is not anError, such asthrow new Point(1, 2), reports[object Object], where Node printsPoint { x: 1, y: 2 }. - Test names: a test without a name, or with an empty one, takes its function's name or
<anonymous>, as in Node, when the function's name is known at compile time: a function expression, a function declaration, or aconstbound to an arrow or anonymous function. A name computed at run time, with a function the program received as a parameter, is used as given, so an empty one stays empty where Node uses the function's name.test(fn)andtest("", fn)with such a function throwSC2020. - Current context:
getTestContext()returns the context of the test, suite or hook whose code is running, as in Node:undefinedat module top level, the root's context in module-level hooks, the suite's in a suite body and in the suite's hooks, and the test's in its body, in the code it awaits, and in the timers, immediates,process.nextTickandqueueMicrotaskcallbacks it schedules. Node returns, for a suite, aTestContextthat is a different object from theSuiteContextpassed to the suite body and itsbeforeandafterhooks; in a compiled program they are the same object, so comparing them with===givestrue. Completion callbacks of callback-style I/O APIs, such asfs.readFile, getundefined, as AsyncLocalStorage stores do. - Test mocks:
mock.fn,mock.method,mock.restoreAllandmock.resetcompile, on the module'smockand ont.mock.mock.methodmocks a function-valued field of a record, such as an object literal or an interface-typed object. Class instances, builtin objects, and object literals whose methods usethisthrowSC2020. Calls through the object record it asthis, including calls of a method read off the object and called on its own, where Node recordsundefined.object.method === mockisfalse, because the field holds a wrapper of the mock.mock.fn()without an original returnsundefinedand records the arguments of each call, as in Node; with a function type whose return type does not includeundefined, such asmock.fn<() => number>(), it throwsSC2020.mock.getter,mock.setter,mock.property,mock.moduleand mock options throwSC2020. - Mock timers:
mock.timers.enable,tick,runAll,reset,setTimeand[Symbol.dispose]()compile, on the module'smockand ont.mock, for thesetTimeout,setInterval,setImmediate,Date,scheduler.waitandAbortSignal.timeoutAPIs.enable()takes no options or an object literal whoseapis, when given, is an array literal. Options andapislists that are not literals, and theMockTimersobject used as a value, throwSC2020. As in Node, the global timer functions,Date.now(),new Date()andscheduler.waitare mocked, and other calls through named and namespace imports ofnode:timersandnode:timers/promisesuse real timers. As in Node, once a reset givesscheduler.waitback, calling it throwsERR_INVALID_THIS. Whilescheduler.waitis mocked, calling it with asignaloption throws anSC2020error. A mock timer's handle converts to a negative number, where Node's mockTimeoutconverts toNaN. When two trackers have timers enabled, clearing a timer through the tracker that did not create it leaves the timer queued, where Node removes the entry at the same queue position in the clearing tracker. - Exit status: Numeric
process.exitCode = valuewrites in statement position set the implicit exit status, whichprocess.exit()uses when called without an argument.process.exit(code)andprocess.exitCodethrow aRangeError(ERR_OUT_OF_RANGE) for a code that is not a safe integer, and convert other codes to int32, as Node does. Readingprocess.exitCodeanswers the assigned code, orundefinedbefore any assignment;process.exit(code)assigns it before the'exit'listeners run. Resets (process.exitCode = undefined) and assignments used as values are unsupported. - Process memory:
process.memoryUsage()readsrssfrom the operating system andheapTotalandheapUsedfrom the runtime's allocator, so the heap figures start near zero and grow as the program allocates.arrayBuffersis the storage of the ArrayBuffers, typed arrays, Buffers, DataViews and SharedArrayBuffers the program holds, andexternalis the same storage without SharedArrayBuffers, as in Node. Node also counts its own startup allocations in both, so a program that holds no such storage reports0where Node reports a few megabytes. In a program with worker threads,externaland the non-shared part ofarrayBufferscount the calling thread's storage. The storage comes from the same allocator, so it also counts inheapTotalandheapUsed. - V8 heap statistics:
node:v8can be imported.v8.getHeapStatistics()returns Node's fields in Node's order, computed from the runtime allocator likeprocess.memoryUsage():total_heap_sizeandtotal_physical_sizeare the bytes the heap holds,used_heap_sizethe bytes allocated,external_memorythe same figure asprocess.memoryUsage().external,heap_size_limitthe machine's memory (the heap has no fixed ceiling), andtotal_available_sizethe limit minus the used bytes. Fields that describe V8 itself (total_heap_size_executable,malloced_memory,peak_malloced_memory, the global handle sizes, anddoes_zap_garbage) are0, andnumber_of_native_contextsis1. The values are approximate and are not V8 heap figures. The othernode:v8members observe the V8 engine, such as heap snapshots, profiles, flags, and serialization, and throwSC2020where they are used. - Performance entries:
performance.mark(),measure(), and thegetEntriesmethods return entries with Node's fields,toJSON(), inspection, and identity.Object.keys,for...in, object spread, andhasOwnPropertyon an entry are unsupported, and an entry stored in anunknownslot prints as a plain object. - Event-loop metrics:
performance.eventLoopUtilization()counts the main thread's CPU time since the event loop started as active time, so blocking system calls count as idle where Node counts them as active.monitorEventLoopDelay()supportsenable(),disable(),reset(),percentile(), and themin,max,mean,stddev,count, andexceedsreadings; the BigInt readings,percentiles, and non-literal option objects are unsupported. - Builtin module lookup:
process.getBuiltinModule()exposes native subsets ofpath,path/posix,path/win32,os, and current-threadworker_threadsmetadata. Stored module references and functions retain identity. Other modules and exports, including storedWorkerconstructors, throwSC2020. DirectWorkerimports use the native worker support described below.process.versionsis a shared dictionary containingnodeandopenssl; other component versions are absent unless defined by the program. - ArrayBuffers and typed arrays: Fixed-length ArrayBuffers support shared typed-array and DataView storage.
Resizing and transferring are unsupported.
Typed code cannot construct
BigInt64ArrayorBigUint64Array; JavaScript that names either one gets the checked-dynamic element kinds, where elements are BigInts.Float16Arraystores IEEE 754 half-precision values, rounding each stored number to nearest-even as Node does;Math.f16round,DataView.prototype.getFloat16andsetFloat16, andutil.types.isFloat16Arraycompile. The typed-array callback methods (forEach,map,filter,some,every,find,findIndex,findLast,findLastIndex,reduce,reduceRight) compile;mapandfilterreturn the receiver's kind, a Buffer for a Buffer, and athisArgargument is unsupported. Numeric typed arrays and Buffers preserve their kind and shared storage throughunknown, including when nested in records and arrays. Numeric typed-array constructors can be stored and used withnew, including constructors read from an array'sconstructorproperty. JavaScript numeric-array parameters and returns preserve typed-array storage.Buffer.from,Buffer.allocUnsafe, andBuffer.concatreturn views into a per-thread pool ofBuffer.poolSizebytes (64 KiB by default) when the size is belowBuffer.poolSize >>> 1, as in Node; a pool slab stays in memory while any of its Buffers does. Node's own startup code allocates from the first slab, so thebyteOffsetof Buffers in that slab differs from Node's. Buffers returned by other Node APIs, such asfs.readFileSyncandzlib, own theirArrayBuffer, where Node allocates small ones from the pool. - Blob and File:
new Blob()andnew File()accept arrays, typed arrays,Set, andMapas sources. Other iterables throwSC2020.blob.stream(),blob.textStream(),URL.createObjectURL(),stream/consumersblob(), and Blob or File fetch bodies are unsupported. Blobs cannot be sent to workers. - Prototypes: Named properties and methods on program class prototypes support replacement, inheritance, and deletion.
A module-level JavaScript class's prototype can become the prototype of other objects:
Object.create(C.prototype),Object.setPrototypeOf(F.prototype, C.prototype),Object.setPrototypeOf(object, C.prototype), andutil.inherits(F, C)with an ordinary constructorF. The inherited methods and accessors run with the inheriting object asthis. Methods that use#privatemembers orsuperthrow a TypeError for a receiver that is not an instance of the class.C.prototypealso reads as a value forObject.getPrototypeOfand for===and!==comparisons. Changing the prototype of a class prototype (Object.setPrototypeOf(C.prototype, X),util.inherits(C, F), orObject.setPrototypeOfon a class prototype reached through an instance) is unsupported. Other bare prototype reflection, TypeScript class prototypes as values, accessor replacement, and prototype storage on local, generic, mixin, or runtime-provided classes are unsupported. Plain objects, arrays, functions, class instances, and Date, RegExp, Map, Set, WeakMap, WeakSet, and Promise values inheritconstructor,valueOf,toString,hasOwnProperty, andpropertyIsEnumerablefromObject.prototypeas in Node, sovalue.constructor === Objectandvalue.valueOf === Object.prototype.valueOfcompare identities exactly. Named reads such asvalue.valueOfanswer these inherited members; computed-key reads such asvalue[key]do not.Object.prototype's own members read as values; its mutation and other reflection, such asisPrototypeOfand__proto__, are unsupported. The constructorsObject,Function,Date,RegExp,Map,Set,WeakMap,WeakSet, andPromiseread as function values; through a stored value onlyObjectcan be called.newthrough a storedObject,Date,Map,Set,WeakMap, orWeakSetbuilds the same value as thenewexpression.newthrough a storedRegExporPromise,newof a storedObjectwith a primitive argument, andinstanceofagainst these constructors are unsupported.instanceof Objectandinstanceof Functionon untyped values follow the prototype chain as in Node, so an object built withObject.create(null)is not anObject. - Intl.Segmenter: Unicode grapheme segmentation, iteration, and
containing()compile, with the default locale or one language tag of the form language[-script][-region] written as a string literal (grapheme clusters do not depend on the locale). Word granularity compiles too, over ICU's UAX #29 word iterator at that locale; its segments carryisWordLikeexactly as Node.js's do. In JavaScript dependencies, sentence segmenters construct, and theirsegment()throws an SC2020 error; in TypeScript sources the construction is refused. Locale negotiation over several locales, sentence segmentation,resolvedOptions(), and detached methods are unsupported. - Globals: Stored
globalThisreferences support identity and probes for absent capabilities. In JavaScript, reading a builtin global through the global object by name (globalThis[name], or a stored global object) answers what the global's own spelling reads, and builtin module members that are global objects in Node, such asrequire("buffer").atobandrequire("timers").setTimeout, are the same values.WebAssemblyread this way, and builtin members read through a global object that untyped code received, can raiseSC2020.for (key in globalThis)visits Node's enumerable globals in Node's order, then the program's own global properties.navigatoranswers Node'shardwareConcurrency,language,languages,platform, anduserAgent, withlanguagederived fromLC_ALL,LC_MESSAGES, orLANGas Node does.navigator.locksraisesSC2020, as doesnavigator.languagefor a locale outside thelanguage_TERRITORY.codeset@modifierform, or one whose language or territory needs ICU's tables (a three-letter territory, for example).Temporalis not defined, as in Node.js 24:typeof Temporalis"undefined",globalThis.Temporalisundefined, and any other use throwsReferenceError: Temporal is not defined. Programs that name it type-check against TypeScript'sTemporaldeclarations. - Map and Set: Keys and elements support numbers and strings by value, and records, classes, arrays, functions, symbols, server handles, and unions of these reference types by identity.
Map values may also be functions.
unknownslots use native checked values, comparing supported primitives by value and retaining supported object references. Typed nested collections other thanMap<unknown, unknown>andSet<unknown>, and promises requiring payload adapters, cannot pass into these slots.Promise<unknown>retains its native representation. Storedkeys(),values(), andentries()iterators compile, retain element identity, and observe live collection mutations until exhausted. They support.next(),for...of, array spreads, and mapper-lessArray.from. They also support the iterator helper methods, such as.map()and.take(). JavaScript sources compile a method value read from Set, Map, WeakMap, or WeakSet: calling it with.callapplies the method to that receiver and throws Node's brand-check TypeError when the receiver is not the matching collection. Typed sources still refuse a method read as a value with SC1090. Constructing a Map, Set, WeakMap or WeakSet, or callingObject.fromEntries, with a checked-dynamic iterable (a native iterator, a generator, or an object with aSymbol.iteratormethod) takes all of its values before adding the first one. When an entry of a Map seed is not an object, the TypeError comes after the iterable is exhausted; Node closes the iterator at that entry. The Set composition methods (union,intersection,difference,symmetricDifference,isSubsetOf,isSupersetOf,isDisjointFrom) accept a Set of the same element type or a Map keyed by it; other set-like arguments are unsupported. - Compression: The one-shot
deflate,inflate,deflateRaw,inflateRaw,gzip,gunzip, andunzipfunctions and theirSyncforms accept Node's options, validated at run time, includingdictionary,maxOutputLength, andrejectGarbageAfterEnd. Typed inputs are strings, Buffers, and Uint8Arrays; untyped JavaScript values may also be other TypedArrays, DataViews, and ArrayBuffers. Theinfooption is unsupported. TheDeflate,Inflate,Gzip,Gunzip,DeflateRaw,InflateRaw, andUnzipstreams, fromcreateGzip()and the other factories ornew zlib.Gzip(), accept Node's options and support writes, piping,pipeline, async iteration,flush,params,close,reset, andbytesWritten. Each output chunk is its own Buffer rather than a slice of a shared chunk-size buffer.zlib.constantsmembers and their module-level copies read as Node's values. The Brotli one-shotsbrotliCompressandbrotliDecompressand theirSyncforms, and theBrotliCompressandBrotliDecompressstreams, accept Node's options, includingparamsanddictionary, and produce the same bytes as Node.util.inspectand Zstd compression are unsupported. - Synchronous iteration: Checked
for...offollows live iterator methods, including compiled class methods and abrupt-completion cleanup. Mapper-less checkedArray.fromaccepts those iterators and plain array-like objects. Sparse checked arrays and general borrowed iterator factories are unsupported. Direct statically typed class loops accept iterators that are class instances or object literals; a loop that exits early calls the iterator's zero-parameterreturn(), as Node's IteratorClose does. - Iterator helpers:
map,filter,take,drop,flatMap,toArray,forEach,reduce,some,everyandfindcompile on generators, on array, typed array, string, Map and Set iterators, and on the objects the helpers return. Helper objects support.next(),.return(),for...of, spreads,Array.fromandyield*, pull their source lazily, and close it (run itsreturn()) at the same points as Node: whentakereaches its count, when a short-circuiting method finds its answer, when a callback throws, and when the loop consuming the helper exits early. In TypeScript,h.return!()andh.return?.()compile whenhis a helper call or aconstinitialized with one.flatMapcallbacks return arrays, generators, Sets or Maps; a string result throws Node's TypeError.Iterator.fromaccepts arrays, strings, typed arrays, Sets, Maps and iterator objects such as generators. In JavaScript, untyped generators and array, string, Map and Set iterators answer the same methods, and array destructuring of untyped values steps generators, iterators, Maps and Sets the way Node does. Helper methods on untyped async generators are unsupported.console.log,util.inspectandObject.prototype.toStringprint iterator objects as Node does:Object [Iterator Helper] {},Object [Generator] {},Object [Array Iterator] {}, and Map and Set iterators with the entries they have left.Iterator.fromover an object with its ownnextmethod or over an untyped value, theIteratorglobal as a value, andString()and template literals of typed iterator objects are unsupported. - Regular expressions: Native checked storage preserves identity,
source,flags, flag properties, and statefultest, and the flag getters (global,unicodeSets, and the rest) compile on statically typed regexes. Staticexec, globalmatch, and numericlastIndexaccess use the native matcher. Runtime constructors accept checked strings and native regex copies;replaceandreplaceAllaccept native regex values with string templates or callbacks, including captures, named groups, and UTF-16 offsets. Named groups (groups) read on matches of a statically known regex: fromexecandmatch, through optional chains (m?.groups?.name), in afor...ofovermatchAll, and on the element parameter of an array-method callback overmatchAllrows. The groups object has a null prototype, as in Node. Non-numericlastIndex, detached methods, andexecthrough an untyped receiver are unsupported. Thev(unicode sets) flag supports class set operations (--,&&), nested classes,\q{...}string literals, and properties of strings such as\p{RGI_Emoji}.new RegExpwith an invalid pattern throws aSyntaxErrorwhose message comes from the native engine and can differ from Node's. Thed(match indices) flag is unsupported: regex literals andnew RegExpcalls with a literal flag string containing it fail to compile with SC1120, andnew RegExpwith a computed flag string containing it throws an error naming the flag. - Object freezing:
Object.freezeandObject.isFrozensupport plain checked dictionaries and primitives. Freezing is shallow and preserves accessors. Aliased typed records, arrays, proxies, and other native objects cannot be frozen. Class instances supportObject.freeze,Object.seal,Object.preventExtensions,Object.isFrozen,Object.isSealed, andObject.isExtensiblewhen the static type of the argument names the class. A write to a read-only field throws Node'sTypeErrorin strict mode code and leaves the field unchanged in sloppy mode code.Object.definePropertywith a string-literal key changes the value,writable,enumerable, andconfigurableattributes of a declared field; an object-literal accessor descriptor (getorset) for a declared field is refused at compile time withSC2020, and another accessor descriptor for a declared field throwsSC2020when the call runs.Object.freeze,Object.seal, andObject.preventExtensionsof a class instance held in an untyped value change the instance itself, so writes through its typed references are checked the same way. A typed record checked from a frozen untyped object (an object literal frozen in a JavaScript file, or a frozenJSON.parseresult) is frozen too, and writes through its typed references are checked the same way. TheTypeErrorfor a write to a read-only property that was added to a class instance through an untyped value names#<Object>where Node names the class. Functions supportObject.freeze,Object.seal,Object.preventExtensions,Object.isFrozen,Object.isSealed, andObject.isExtensible; the operations apply to the function's own properties (name,length,prototype, and the ones a program assigns). Class constructors are not supported. A write to a read-only property of a checked dictionary or a function throws aTypeErrorwhose message omits Node's'x' of object '#<Object>'(orof function '…') suffix. A JavaScript class field that is first created after its instance became non-extensible is added instead of throwing.
Builtin function values
Some builtins can be stored and passed as functions:
- Lowered
node:pathfunctions across the bare, POSIX, and win32 modules, including optionalbasenameand variadicjoin/resolve. Called through an untyped value, they validate their arguments with Node'sERR_INVALID_ARG_TYPE. A path module held by untyped code is a plain object with Node's members in Node's order. - Supported zero-argument
node:osfunctions andquerystring.escape/unescape. util.isDeepStrictEqual,styleText,stripVTControlCharacters,toUSVString,inherits,deprecate,callbackify,debuglog, anddebug.fs.existsSync,unlinkSync,chmodSync,chownSync,renameSync, andcloseSync, andfs/promises.unlink,chmod, andrename.
In JavaScript, setTimeout, setInterval, setImmediate, clearTimeout, clearInterval, clearImmediate, queueMicrotask, and process.nextTick are function values wherever they are stored, including conditional and logical expressions and assignments: typeof answers "function", identity holds across spellings, and calls schedule as the direct calls do, returning the same numeric timer handles.
Calls through these values bypass node:test mock timers.
In JavaScript, atob, btoa, and structuredClone are function values the same way, and calls through them run what the direct calls run.
In JavaScript, parseInt and parseFloat are the Number.parseInt and Number.parseFloat function values, isNaN, isFinite, and Symbol (with Symbol.for, Symbol.keyFor, and the well-known symbols) are function values whose calls run what the direct calls run, and Atomics is an object whose integer operations run.
Calling eval through its value throws the EvalError its direct calls throw.
escape, unescape, WeakRef, and AsyncDisposableStack have function values with Node's name and length that throw SC2020 when called or constructed.
globalThis.require, module, exports, __dirname, and __filename are undefined, as in Node.
Other builtin globals stored in JavaScript remain opaque identity values.
In JavaScript, require("events") and the EventEmitter class assigned to an untyped binding or stored in an object (ReleaseEmitter = EventEmitter) are the untyped EventEmitter constructor that constructor functions inherit from (see below): new through it builds such an emitter object, and identity and instanceof agree with the class.
A class can extend require("events") directly.
Other immutable aliases of table-backed Node builtins support direct calls, but cannot be passed elsewhere.
util.promisify supports compile-time conversions of child_process.execFile, child_process.exec, setTimeout and setImmediate (to the timers/promises functions, as in Node), stream.finished and stream.pipeline (to the stream/promises functions, as in Node), the zlib callback one-shots deflate, inflate, deflateRaw, inflateRaw, gzip, gunzip and unzip (with or without options), the crypto callback functions randomBytes, pbkdf2, scrypt, hkdf, randomFill, randomInt and generateKey, dns.lookup (settling with { address, family }, or the address array with all: true) and dns.lookupService (settling with { hostname, service }), and the fs callback functions that have an fs/promises counterpart (access, appendFile, chmod, chown, copyFile, lchown, link, lstat, lutimes, mkdir, mkdtemp, readFile, readdir, readlink, realpath, rename, rm, rmdir, stat, statfs, symlink, truncate, unlink, utimes, and writeFile); calls through the converted function lower as the fs/promises call.
util.promisify over an untyped function (a value typed any, a function whose parameters are untyped, or any other target in JavaScript) returns a native wrapper that follows Node's callback rules and carries the original's name and length, and throws Node's ERR_INVALID_ARG_TYPE for values that are not functions.
Such a function with other own properties, util.promisify.custom among them, throws SC2020 where util.promisify runs, and the wrapper does not report Node's DEP0174 warning when the original returns a promise.
util.styleText supports standard formats and aliases, #RGB and #RRGGBB hex colors, arrays of formats, nested ANSI resets, and explicit color enabling with { validateStream: false }.
Native calls accept standard process streams; custom native streams and mutations to util.inspect.colors remain unsupported.
util.inherits links the prototypes of constructor functions, and util.deprecate, util.callbackify, and util.debuglog return native function values that forward receivers and arguments.
In JavaScript, a constructor function can inherit from EventEmitter, the legacy Stream constructor, or a stream class through util.inherits or Object.setPrototypeOf.
EventEmitter.call(this) and Stream.call(this) initialize the object as Node does, and its listener methods keep their state in the object's own _events, _eventsCount, and _maxListeners properties.
The captureRejections option and events.errorMonitor listeners are not supported on such objects.
Readable.call(this, options) and the same call on Writable, Duplex, Transform, or PassThrough give the object a native stream.
The stream calls the object's _read, _write, _final, _transform, _flush, and _destroy with the object as this, and the stream prototypes' methods and accessors work on it.
Its listeners live in the native stream rather than in _events, and _readableState and _writableState are read-only views that answer the commonly read fields.
Typed code that receives such an object as a stream class uses its native stream, and piping a native stream into it works.
The options the native streams refuse (signal and others) are refused here too, as are _writev on a Transform, _final on a Transform, symbol event names, listeners(), rawListeners(), wrap(), and pipes into a destination that overrides write() or end().
_construct and _writev are read when Readable.call(this, options) or Writable.call(this, options) runs, as Node's constructors read them.
Other class constructors passed to util.inherits or util.deprecate are refused.
Deprecation warnings are emitted on the next tick and follow assignments to process.noDeprecation and process.throwDeprecation; compiled binaries take no Node command-line flags such as --no-deprecation or --trace-deprecation, and process.traceDeprecation is unsupported.
A stored util.deprecate reports a length of 4, where Node reports 3.
In TypeScript, a util.callbackify result must reach a callback whose error parameter accepts null; the @types/node overloads that type it as non-null are refused.
util.debuglog reads NODE_DEBUG as the process started.
Its %s refuses functions and objects with symbol-keyed members, %o refuses objects, and object arguments are refused on a color terminal.
util.isDeepStrictEqual supports primitives, ordinary records and arrays, cycles, enumerable string and symbol properties, and byte views.
Its optional third argument skips prototype and constructor comparisons.
Structural comparisons of native Maps, Sets, class instances, Errors, proxies, accessor properties, and function-valued own constructor properties remain refused.
Synchronous and promise filesystem APIs with trailing arguments that affect behavior remain call-only. This includes writers, open, directory creation/removal, metadata readers, and directory readers. Passing them as values could discard modes, flags, encodings, or options during function-signature adaptation.
Native error-first filesystem callbacks can be stored and passed to platform adapters.
Reads support Buffer and UTF-8 results; writes preserve string flags and modes; copy follows fs.cp.
Reads and writes reject already-aborted signals, but native file operations complete synchronously before the deferred callback, so cancellation cannot interrupt I/O in progress.
Recursive directory reads and Dirent results report a native limitation.
fs.glob compiles only as a direct call; a stored fs.glob value throws SC2020.
Native worker threads
node:worker_threads runs workers as native threads.
Worker entry points must resolve at build time: use a source-relative new URL("./worker.ts", import.meta.url), the current module URL, an absolute path, or CommonJS __filename.
Each worker initializes its own module state, event loop, environment snapshot, and reference-counted heap.
Nested workers inherit their parent's environment snapshot.
Supported constructor options are workerData, argv, a transferList of MessagePorts, name (reported by threadName and worker.threadName), stdout, stderr and stdin, and resourceLimits.stackSizeMb, which sets the worker thread's stack size (at least 192 KiB; without it a worker's stack is 8 MiB, where Node's is 4 MiB).
The resourceLimits heap limits (maxOldGenerationSizeMb, maxYoungGenerationSizeMb, and codeRangeSizeMb), worker.resourceLimits while the worker runs, and resourceLimits read inside a worker are refused; in the main thread resourceLimits is {}, and after a worker exits worker.resourceLimits is {}, as in Node.
With the stdout or stderr option, the worker's writes to that stream reach worker.stdout or worker.stderr, a Readable that ends after the worker's 'exit' event; its chunks arrive in order with the worker's other events.
Without the option a worker writes to the process's own output, and reading worker.stdout or worker.stderr is refused.
With the stdin option, worker.stdin is a Writable whose chunks the worker reads from process.stdin, in order with the worker's other events, and process.stdin ends when worker.stdin ends; without it worker.stdin is null and the worker's process.stdin ends without data, as in Node.
Runtime paths, eval, loaders, and shared environments are unsupported.
setEnvironmentData and getEnvironmentData keep a map per thread with SameValueZero keys; each new Worker starts from a clone of its parent's entries taken by the constructor, which throws DataCloneError when an entry cannot be cloned.
Worker argument strings containing null bytes are also unsupported.
Workers support online, message, error, and exit events, postMessage, terminate, ref, and unref.
worker[Symbol.asyncDispose]() terminates the worker and resolves with undefined after its exit event, so await using disposes a Worker at the end of its block.
A worker's uncaught exception reaches its error listeners as Node's error serializer sends it: an Error keeps the nearest of Error and its six native subclasses (an AggregateError arrives as an Error named AggregateError) along with its name, message, cause, and other data properties and their enumerability, and other thrown values clone as messages do.
An unhandled rejection whose reason is not error-like arrives as an UnhandledPromiseRejection Error with code ERR_UNHANDLED_REJECTION quoting the reason.
A thrown value that does not clone, such as a function, arrives as an ERR_WORKER_UNSERIALIZABLE_ERROR Error, where Node sends its util.inspect string.
new MessageChannel() from node:worker_threads makes two entangled MessagePorts, in one thread or across threads once a port is transferred, with receiveMessageOnPort.
Port messages arrive in Node's order: each port's queued messages as one batch before setImmediate callbacks, a port's own 'close' after the poll phase, and the other port's 'close' after its queued messages while the loop keeps running.
A worker's messages to its parent, and the parent's messages in the worker, also arrive as one batch before setImmediate callbacks, each followed by its microtasks, as in Node: the messages queued when delivery starts, and those that arrive meanwhile until the batch holds 1000.
receiveMessageOnPort(parentPort) in a worker takes the parent's next message.
A port's onmessage property and addEventListener are unsupported.
BroadcastChannel delivers each message to every other open channel with the same name, in any thread, as a 'message' MessageEvent through onmessage and addEventListener; an open channel keeps the process alive until close() or unref().
A messageerror event is never dispatched.
The parent port supports message listeners, postMessage, close, start, ref, unref, and hasRef.
Messages clone primitives, plain object graphs, arrays, errors, ArrayBuffers, typed arrays, and DataViews, preserving cycles and aliases.
Program class instances arrive as plain objects with their own data properties, without their prototype, methods, accessors, or private fields, as in Node.
markAsUntransferable marks objects for the current thread, and a marked ArrayBuffer or MessagePort in a transfer list throws DataCloneError, as does the ArrayBuffer of a pooled Buffer; marked objects other than ArrayBuffers stay alive until their thread exits.
markAsUncloneable marks a plain object, an error, or a class instance, and structuredClone and postMessage then throw DataCloneError for it, also where it is nested; as in Node, the mark has no effect on primitives, arrays, typed arrays, and ArrayBuffers.
A plain object that the compiler copies into a container with a fixed element type, such as an array literal whose elements all have one shape, is a separate object in the copy, which is not marked.
Marked objects stay alive until their thread exits.
A MessagePort travels with a message when the message's transfer list (an array or { transfer }) names it, and the sending port is unusable afterwards; a port in a message without that listing throws DataCloneError.
Other transferable values, functions, proxies, and other native handles are refused.
SharedArrayBuffers share their backing storage while retaining separate wrappers in each thread.
Graphs made immutable with @scriptc/threads are passed by reference instead of cloned; see Sharing Data Between Workers.
SharedArrayBuffer storage is fixed-length.
Atomics supports integer load, store, exchange, compareExchange, add, sub, and, or, and xor over 8-, 16-, and 32-bit integer arrays.
wait and notify use Int32Array views; BigInt atomics, waitAsync, and growable buffers are unsupported.
Atomics operations run as sequentially consistent atomic instructions and take no lock.
Other reads and writes of shared storage access each element atomically; a copy, fill, or conversion that runs while another thread writes the same storage can observe some of those writes, as in Node.
terminate unwinds at runtime checkpoints, including loops and parked atomic waits, without running JavaScript catch or finally blocks.
Blocking native calls finish before the next checkpoint.
Workers are unsupported in WASI, compiled libraries, and executables that use foreign-thread native callbacks. Ordinary callbacks that run on their owning script thread remain supported. Shared byte storage cannot expose unmanaged FFI pointers; copy it into an ordinary Buffer before passing it to native code.
Child-process workers
child_process.fork() requires a worker path resolved at build time from new URL("./worker.ts", import.meta.url) or fileURLToPath(new URL("./worker.ts", import.meta.url)).
Never-reassigned const aliases and statically resolvable template parts are accepted.
The worker and its imports are embedded in the executable, which re-executes itself to start that module.
Worker arguments begin at process.argv[2].
Supported options are default inherited stdio or an inline object with cwd, env, silent, windowsHide, or [stdin, stdout, stderr, "ipc"].
execArgv is accepted but has no native effect.
Runtime worker paths, custom execPath, advanced serialization, transferred sockets or servers, uid/gid, timeout/signal options, and other stdio arrays are unsupported.
Parent and child channels support send(message, callback?), connected, disconnect(), and on/once for message and disconnect.
Message listeners may return void or Promise<void>.
Messages use newline-delimited JSON, so their static types must be JSON-stringifiable or unknown backed by a checked JSON tree.
send() returns the channel's backpressure state and invokes its callback later with null or an Error.
disconnect() changes connected synchronously, before the later disconnect events.
A 'data' listener on a child's stdout or stderr whose chunk is unknown or any receives strings when a setEncoding() statement on the same stream precedes it in its block or an enclosing block, and Buffers when the function never calls setEncoding() on that stream.
Any other placement of setEncoding() is refused at compile time, and a setEncoding() call that runs elsewhere afterwards makes the listener throw a TypeError instead of receiving strings.
An inline 'exit' or 'close' listener may declare (code: number, signal: string), which TypeScript accepts through the catch-all on overload; it receives the null values Node passes, and a typed use of a null value throws a TypeError.
Untyped values
Supported uses of any use native checked values.
Operations without native lowering produce diagnostics such as SC2011.
Use unknown with a checked cast where an operation needs a concrete type.
Map and Set type arguments may use any, with the same checked storage as unknown.
Locals, parameters, and returns can carry untyped values; record and tuple fields can hold unknown.
JavaScript instance fields and TypeScript class fields declared unknown or object (also with null or undefined, or as arrays of those) can also hold native checked values.
Bare fields start as undefined, and redeclaring a field with the same checked-value type resets it in initialization order.
Explicit TypeScript any class fields, other checked-value static fields, statically typed array elements, and union members are unsupported.
Program class instances retain identity through unknown and casts back to their exact class or a base class, including classes with internal collections.
Inspecting dynamic properties throws a catchable TypeError if the class's fields cannot pass through checked storage.
Supported native handles also retain identity.
JavaScript argument and return conversions preserve native array references; other JSON-shaped record and array conversions can copy values.
Supported operations on unknown include truthiness, typeof narrowing, property access, +, switch, and throw.
Cast before using other operations.
In JavaScript, a call whose untyped argument could select an overload with another result type returns a checked value, whichever overload the type checker picks, and so do the unannotated bindings and functions that hold or return it.
In TypeScript, an any argument keeps the overload the type checker picks, and a value that selects another overload at runtime throws a TypeError where the result is used.
Type checking
scriptc checks programs against the es2025 standard library, the ESNext declarations for Array.fromAsync, explicit resource management and Error.isError, and its own ambient declarations.
Some declarations differ from TypeScript's standard library or @types/node: JSON.parse returns unknown, and a Promise executor's reject reason is typed as Error.
A program that passes its project's TypeScript check may still use unsupported operations.
A second preflight using the project's declarations distinguishes those sites from ordinary type errors and reports scriptc diagnostics with rewrite hints.
Declared APIs without a compiler implementation, such as unsupported console members, produce SC2020.
Contract types
Contract types are checked only where they are written as the annotation of a parameter, variable, class instance field or function result, Acyclic only on classes, interfaces and object type aliases, and ProgramLifetime only in the implements clause of a class declaration; other aliases, interface members and nested type positions are reported.
In programs that use worker threads, a surrounding try/catch does not discharge NoThrow.
Int32 refuses parameters of functions used as values and fields of classes whose instances are stored in any or unknown values.
Int32[] refuses arrays that can come from or escape to code scriptc cannot see, follows callback results only for callbacks written at a map or filter call that scriptc runs inline, and checks a copy made by slice or a spread as if it were its source array.
Element reads that find a value are int32s, but a scalar Int32 slot still needs a[i] | 0, because a read can miss and produce undefined.
Immutable refuses values stored in any or unknown or that another reference can still change.
ProgramLifetime applies to root classes of executables only; instances the program drops are never reclaimed unless they belong to a released lifetime region.
three.js
With --npm-static=three, native and WASI builds support published package imports and tested CPU workflows for math, bounds, procedural geometry, curves, shapes, extrusion, text geometry, scene graphs, cameras, lights, materials, textures, and render-target data.
Mesh workflows include instancing, batching, morph targets, skeletal deformation, LOD, and sprites.
Raycasting includes mesh intersections, sorted results, recursive traversal, layers, distance limits, camera rays, lines, and points.
Animation coverage includes tracks, clips, property binding, mixer playback, blending, and fading. In-memory loading covers scene, material, geometry, and animation JSON, OBJ, STL, PLY, and self-contained glTF/GLB scenes with buffers, PBR material data, and animation. This establishes the exercised workflows, not every loader extension or overload.
Tested CPU graph construction from three/webgpu and three/tsl includes scalar/vector nodes, mutable uniforms, Fn layouts and calls, and MeshBasicNodeMaterial data.
WebGL/WebGPU rendering, DOM controls, image and video resources, audio, and worker-based decoders require external host bindings. A browser or native application can render geometry and material state produced by a compiled library and receive its resource lifecycle notifications. Compressed model and texture decoding belongs to that host; shader execution and rendered output are outside the CPU coverage described here.
Runtime differences from Node.js
Compiled code has runtime behavior that can differ from Node.js. Account for the following differences when porting a program.
- Event order across native code and islands: Timers, worker output, and other macrotasks from the program and from JavaScript it runs in a Node island share one event loop under Node.js, so their order is fixed. A compiled program runs both on the event loop it hosts for Node.js, but it does not merge them into one order, so callbacks from the two sides can run in a different order than under Node.js, and the order can vary between runs. Only programs that depend on the ordering between native and island callbacks are affected.
Array bounds and runtime errors
Typed-array reads at an index that is not an integer in the array's range return undefined, as in Node.js, and invalid numeric indexed writes are ignored, while the assignment expression retains its original value.
A non-null assertion on such a read (bytes[i]!) yields NaN instead of undefined.
Ordinary arrays track holes separately from present undefined values.
Missing reads and empty pop()/shift() return undefined, indexed writes can grow the array, and length growth creates holes.
Keyed reads of a Record or an index signature return undefined for a missing key, as in Node.js, with or without noUncheckedIndexedAccess.
A missing array element or key that reaches storage that cannot hold undefined, such as a class field typed number, throws a TypeError.
Runtime traps cannot be caught.
User-thrown values and supported exceptions, including JSON parse, checked-cast, filesystem, regex, and String.prototype.repeat count errors, can be caught; hard traps such as out-of-range reads of statically typed ordinary arrays terminate the process.
Deep recursion in Linux and macOS executables throws Node's catchable RangeError: Maximum call stack size exceeded, on the main thread, in worker threads, and inside async functions and generators.
The depth at which it is thrown differs from Node: the main thread uses the process stack limit (usually 8 MiB), worker threads get an 8 MiB stack, async functions and generators that keep a fiber run on 512 KiB stacks, and stackless ones run on the stack that resumes them, so native code usually recurses deeper than Node on threads and somewhat less deeply inside fiber bodies.
Recursion inside runtime library operations, such as serializing deeply nested data, is not checked.
Windows executables, WASI builds and library builds do not check the stack, and exhausting it there terminates the process.
Runtime type checks
Casts from values whose type is only known at runtime validate the value.
For example, JSON.parse(s) as Config throws a catchable error if the data does not match Config, identifying the offending path, such as expected number at $.port, got string.
A TypeScript assertion alone does not perform this validation when run under Node.js.
A record or class instance cast from unknown to a dictionary type such as Record<string, number> keeps its identity, and the cast does not validate it.
Reading a value that does not match the dictionary's value type throws a TypeError, such as expected number at $, got string, where Node.js returns the value.
Casts between program classes are checked too: casting an instance to a class it does not extend throws a TypeError, where Node.js reads the members structurally.
SC6004 reports calls that pass such an instance to a function that casts it.
A Promise converted from unknown to a typed result validates its fulfilled value.
A mismatch rejects with a TypeError.
Rejection reasons and reference equality are preserved across conversions.
A non-null assertion (value!) checks the value when it extracts an object, array or other non-nullable member from a union.
If the value holds null or undefined, the assertion throws a TypeError, even when the result is never used; Node.js continues until a property of the value is read.
Record identity and property order
A record converted to a record type with a different set of properties, such as a narrower shape or one that adds optional properties, is copied.
Mutations through the converted reference do not affect the original, and the copy is not === to it.
Empty record layouts are also snapshots because they have no property storage.
scriptc coverage and scriptc build report SC6001 where a copied value is then written or compared, whether the record was passed as an argument, stored in a typed binding, asserted with as, assigned to a typed binding later, or stored as an element of a typed array literal.
Typed records with declared fields, indexed records, and arrays retain identity and mutations through native checked storage.
A record or class instance converted to a string-keyed dictionary type such as Record<string, string>, directly, through a {}, object or unknown binding or parameter, or as an element of a constant unknown[] array that holds such records, keeps its identity when the program writes through, compares or inspects values of that dictionary type.
Every dictionary type with the same value type then uses checked dynamic storage, which is slower than a native dictionary.
Class instances retain identity at their exact type or a base class, and at any interface or object type that a class instance is passed, stored, returned, or asserted as when the program could tell a copy from the instance: values of such a type are checked views of the original object, so writes, identity comparisons, Set and Map keys, util.inspect, and JSON.stringify through them reach the instance, as in Node.js.
These types use checked dynamic storage, which is slower than native record fields, for all of their values, including plain objects.
A type whose values are only read field by field, from fields the class does not write after construction and does not implement as accessors, stays a native record and holds a copy.
Object spread of a class instance is refused.
Dense array literals created directly in checked storage preserve identity, and supported native handles pass by reference.
Object.keys, Object.values, Object.entries, for...in, JSON.stringify, and util.inspect enumerate a record's keys in the order the object created them, as in Node.js.
scriptc chooses one order per record type from the order in which the program's object literals create the keys, follows object spread, rest destructuring, and record conversions back to the values they copy, and places an optional key that the program assigns after construction after the keys the object was built with.
When the object literals of one record type create its keys in different orders, including literals of two types with the same properties and property types, each value records the order its literal used: copies made by object spread, rest destructuring, and record conversions keep their source's order, and assigning an optional key the object lacks, including after delete, moves the key last.
A type keeps the declaration order of its first type, and SC6002 reports object literals whose order differs where the program observes it, when one of its values gets its keys from a spread whose source order is not known, from a spread that also sets an optional key the source lacks, or from a copy of a value scriptc cannot trace, or when the type's values can take more than 16 orders.
A record converted from a checked value, such as const rows: { score: number }[] = JSON.parse(text), keeps the properties its type does not declare.
So does a record converted from an object with more properties, such as const p: { a: number } = { a: 1, b: 2 } or an argument passed to a parameter of a narrower type.
JSON.stringify, Object.keys, Object.values, Object.entries, for...in, in, hasOwnProperty, propertyIsEnumerable, Object.hasOwn, util.inspect, and untyped views of the record see them, together with the declared fields, in the source object's key order.
String conversion, +, and calls of toString and toLocaleString run the source object's own toString or valueOf when it has one.
Calling valueOf or isPrototypeOf by name on a record type that such an object converts into reports SC1090 when the object has its own property of that name.
Object.values and Object.entries check those values against their static result type and throw a TypeError if one does not fit.
For a record converted from an object with more properties, these surfaces read the object's other properties when they run, so later writes to those properties are visible; the declared fields are a copy taken at the conversion.
Copies of such a record made by object spread, Object.assign or rest destructuring contain only the declared fields; a conversion to another record type keeps the properties too.
Index-signature records list declared fields before the other keys.
Optional fields and properties added through a record's unknown view can be deleted.
A required field has no absent state, so deleting it through the view throws TypeError: Cannot delete property 'x' of #<Object> and leaves the record unchanged, where Node.js removes the property.
Records inherit toString, toLocaleString, valueOf, hasOwnProperty, isPrototypeOf and propertyIsEnumerable from Object.prototype.
A call of one of these methods by name runs the built-in with the record as its receiver, unless the record holds an own function under that name.
A keyed read such as handlers[name] of a record whose values are functions answers the built-in when the record lacks the key, so truthiness, typeof and calls match Node.js.
A keyed read of a record whose values are not functions, such as counts["toString"] on a Record<string, number>, answers undefined where Node.js answers the inherited function, so counts[word] ?? 0 counts such a word as new.
Calling a built-in read from a record of functions throws a TypeError when its answer does not fit the record's function type, for example valueOf read from a Record<string, (x: number) => number>.
Other inherited names, such as constructor, read undefined from typed records.
Buffer construction
Buffer.from accepts untyped strings, byte arrays, arrays, and plain array-like or Buffer JSON objects.
Encoding arguments must be supported literals.
Buffer.from(arrayBuffer, byteOffset, length) is a view of the ArrayBuffer or SharedArrayBuffer, with Node's offset and length checks.
Custom input valueOf hooks and opaque class or native-handle inputs throw an unsupported-operation error.
The deprecated Buffer() and new Buffer() take up to three arguments, without spreads, and follow Node: the first call made outside node_modules reports DEP0005 on the next tick, a number allocates zero-filled bytes, and other arguments convert as Buffer.from does.
In JavaScript, Buffer read as a value (the global or the buffer module's Buffer) is one function with Node's statics and poolSize.
Calling or constructing it through a stored value, reading its prototype, and its copyBytesFrom and of statics throw an unsupported-operation error.
Buffer.prototype members read as values are functions that run on Buffer receivers; inherited and symbol-keyed members throw an unsupported-operation error.
readable-stream
readable-stream 2.x, 3.x and 4.x compile as Node.js's built-in stream module.
For 2.x and 4.x, that is the package's own behavior when the READABLE_STREAM environment variable is disable.
Without that variable, Node.js runs the package's JavaScript copy of the stream classes, so a native build can differ from Node.js wherever a program depends on that difference: instanceof checks against the built-in classes, class identity, error messages, and timing details.
The package's lib/_stream_*.js files also compile as the matching built-in classes, although Node.js loads the package's own implementations through them in every environment.
readable-stream 3.x is a copy of Node.js 10's streams.
Its own disable mode throws on Node.js 24, so no setting makes Node.js run it against the built-in classes; a native build maps the members its entry exports (the stream classes, Stream, finished and pipeline) to the built-in ones.
HTTP headers
Without @types/node, the bundled declarations type every req.headers value as a string.
Reading headers["set-cookie"] is then refused, and a { ...req.headers } copy holds set-cookie as one string joined with ", ", where Node holds an array.
Read headersDistinct["set-cookie"], or install @types/node, whose headers["set-cookie"] is string[].
JSON callbacks
Function replacers and two-argument revivers support nested replacements, object-property deletion, and thrown exceptions.
Omitting the root through a replacer returns undefined.
Array replacers list the object keys to serialize, as in Node.js.
Stored JSON.stringify functions accept numeric and string indentation; direct calls require literal indentation.
Reviver source contexts are unsupported. A reviver that deletes an array element throws, because checked arrays cannot represent holes.
Callback values use checked storage.
Typed records and arrays retain identity and mutations; record fields use declaration order; typed-array views retain backing storage and brands.
Buffer.isBuffer preserves the Buffer brand through unknown.
JavaScript callbacks receive the holder as this; TypeScript callbacks that access dynamic this are unsupported.
Strings and sorting
Strings are stored as UTF-8, with lone surrogates kept as their own code units.
Length, string methods and relational comparisons such as < and > use UTF-16 semantics, including for lone surrogates.
split with a string separator and replace or replaceAll with a string pattern don't match a lone surrogate against half of a surrogate pair; regular-expression patterns do.
Output, file contents, and other encoded text write each lone surrogate as U+FFFD, as Node does.
File system paths and network host names that contain a lone surrogate reach the operating system unconverted.
One-argument localeCompare follows Node's default root-locale collation for Latin-script text (ASCII, Latin-1 Supplement, Latin Extended-A, combining diacritical marks, and U+2044 FRACTION SLASH): letters order before case and accents, so "a".localeCompare("B") is -1.
Strings containing other characters compare by code point, which can differ from Node's ICU collation; SC6003 reports such string literals.
The locales and options arguments are unsupported.
sort and toSorted use stable natural merge sort.
Default ordering supports string, number, and boolean arrays, comparing their string forms in UTF-16 order; for example, [2, 10, 1].sort() produces [1, 10, 2].
sort preserves holes at the end, while toSorted produces a fresh array with holes filled by undefined.
With an explicit comparator, consistent comparators produce the same sorted results as Node, but callback order and count can differ.
Typed-array sort and toSorted order numbers by default, with -0 before 0 and NaN last.
With a comparator, they call it in the same order as Node and write the sorted values back after the last call.
Published graphs
Graphs published with @scriptc/threads are immortal: scriptc never frees them, even after every thread has stopped using them.
Publish long-lived data, not per-request messages.
A receiving thread reads the sender's objects, so they keep their classes, methods, and identity across threads and across messages. Node.js delivers clones without prototypes, a new clone for every message.
Writes into published objects throw Node's frozen-object TypeErrors.
In Node.js, o.x = f() evaluates f() before the write fails, and scriptc does the same, except for writes to union-typed class fields and for Map, Set, and array mutator methods, where the write check runs before the arguments are evaluated.
Private fields (#x) of published objects cannot be written either, although Node.js allows writing private fields of frozen objects.
Dates and timezones
String constructors and Date.parse use V8's date-string grammar: ECMAScript date-time strings and the legacy forms Node.js accepts, such as RFC 1123 HTTP dates (Mon, 01 Jan 2024 00:00:00 GMT), Date#toString output, and Jan 2, 2024.
Strings without a timezone, and new Date(year, monthIndex, ...) fields, are local time.
Local calendar getters and local-time conversions use the operating system's timezone database. Historical results can differ from Node.js when timezone data differs. For valid extreme years outside a platform calendar API's range, scriptc uses a calendar-equivalent year in the 400-year Gregorian cycle to obtain the timezone rule.
toString, toTimeString, String(date) and template literals print the zone's long name after the GMT offset, as Node does (GMT-0500 (Central Daylight Time)). scriptc identifies the zone the way Node does, from TZ when it names a zone, else from /etc/localtime.
Outside Windows, a write to process.env.TZ changes the zone for later conversions and getters.
The names are the en-US names for the IANA zones; Node prints them in the language of the locale that LC_ALL, LC_MESSAGES or LANG selects, so with a non-English locale the name differs from Node's.
A TZ value that is a file path or a POSIX rule string (such as EST5EDT,M3.2.0,M11.1.0) gives offsets and names that differ from Node's, which ignores those forms.
On Windows, the name is the GMT+hh:mm form unless TZ names a zone.
On wasm32-wasi, local time is UTC and the name is Coordinated Universal Time.
Weak collections and memory
WeakMap and WeakSet accept checked native objects and arrays, functions, numeric typed arrays, ArrayBuffers, native weak collections, and typed records, arrays, tuples, and classes that preserve identity through checked storage.
Copied values, other native handles, and symbol keys are unsupported.
Constructor seeds support arrays; custom iterators and detached methods are unsupported.
Weak collections do not retain their keys, but values that refer back to a key can keep it alive until deletion or collection release.
FinalizationRegistry keeps its registrations: register and unregister check their arguments and answer as in Node.js.
Its cleanup callbacks never run, which the ECMAScript specification allows.
Program output matches Node.js, which runs cleanup callbacks only when its garbage collector decides to.
Memory that a package frees only from a cleanup callback is not reclaimed until the program exits.
For example, a wasm-bindgen package frees the WebAssembly memory behind a wrapper object from its cleanup callback, so a long-running server that drops such wrappers without calling their free() method keeps that memory.
Call free() on wrappers the program no longer needs.
Symbol targets and unregister tokens are unsupported.
WeakRef is unsupported.
Memory uses reference counting. Acyclic values are freed deterministically, and cycles are collected at defined collection points. Native checked objects, arrays, Sets, and captured closures participate in cycle collection. Cycles through opaque native capsules can remain allocated.
Foreign-thread callbacks
FFI format 5 accepts retained, context-bearing void callbacks invoked by library-owned threads.
The native callback copies arguments and queues work; the script closure runs on the event loop at least one turn later.
These callbacks are not suitable for real-time execution.
Value-returning callbacks and direct script execution on foreign threads are unsupported. Reference counting and exception state belong to the script thread, and waiting for the event loop can deadlock.
TLS ciphers
Before the handshake Node's tlsSocket.getCipher() returns undefined, and after close null.
Its declared result is the { name, standardName, version } record, so a typed read there throws a TypeError instead.
After the handshake the record matches Node, with OpenSSL's suite name in name.
The suite itself is the one the bundled mbedTLS negotiates, which can differ from OpenSSL's choice for the same peers.
TLS certificates
tlsSocket.getPeerCertificate(), getCertificate(), getPeerX509Certificate(), and getX509Certificate() follow Node, including the detailed issuer chain, on sockets whose type is known.
On a TLS socket held in an unknown or any value, or in an untyped JavaScript parameter, they throw an error that names the call as not supported.
Client certificates follow Node: tls.createServer, https.createServer, and new tls.TLSSocket take requestCert, rejectUnauthorized, and ca, and tls.connect and https.request take cert and key.
A server's authorized and authorizationError report the client certificate's verification as Node does, and a server, client, or tls.createSecureContext given a ca also sends the chain it completes, as OpenSSL's automatic chain does.
A server verifies client certificates against the ca of the context it serves, including contexts from addContext() and setSecureContext(): an empty ca (an empty Buffer or array) trusts no certificate, and an omitted ca trusts the default CAs.
The same holds for a client's ca in tls.connect, https.request, and http2.connect, where an empty string is no ca, as in Node.
In http2.connect, a ca held in an unknown or any value that is an empty string is refused.
requestCert beside a TLSSocket's secureContext or an SNICallback, client certificates on http2 secure servers, and a cert without a key (or the reverse) are refused.
server.addContext() and server.setSecureContext() follow Node on tls and https servers, including wildcard names, which match one label without regard to case.
A name with regular-expression groups or alternation, or one outside ASCII, is refused, as are both methods on a server that is not a tls or https server.
The 'tlsClientError' event reports Node's error for a failed handshake: OpenSSL's code and reason, or socket hang up for a client that leaves.
OpenSSL's messages leave out the thread identifier Node prints before error: and the source location after the reason.
A failure whose OpenSSL reason the runtime does not know, such as a malformed client hello, is reported as an error with code SC2020 that says so.
The X509Certificate those accessors return has the same refusals as any other certificate (see Crypto), so in JavaScript narrow it, for example with if (cert), before reading its fields.
TLS sessions
TLS servers send no session tickets, so a connection to them cannot be resumed.
A client's 'session' event fires once per connection, when its handshake finishes and before secureConnect.
Node fires it for each ticket the server sends, after secureConnect, and OpenSSL servers send two.
Console and process streams
console.log, info, and debug write to stdout; error and warn write to stderr.
They accept unknown, printing strings verbatim and other values through native util.inspect.
Direct calls support global console and node:console imports.
Console output, util.format, and util.formatWithOptions with a format string known only at run time, spread arguments, or an options object format their arguments at run time.
There, %s of a function or of a class instance whose class defines toString and %o of an object throw SC2020.
util.inspect with colors, with option values known only at run time, or in the inspect(value, showHidden, depth, colors) form renders the value's untyped view in the runtime with Node's styles.
Colored output of errors, promises, regular expressions, DataView, ArrayBuffer, weak collections, iterators, and other native objects throws SC2020.
Inspect options other than depth, colors, customInspect, compact (a number or false), breakLength, maxArrayLength (a non-negative integer or null), and sorted (a boolean) throw SC2020 when they are set to a value other than Node's default.
util.inspect calls [util.inspect.custom] methods of classes and objects with Node's depth, options, and util.inspect arguments, and console.dir and customInspect: false skip them.
A class instance with such a method that is held as an untyped value throws SC2020 when it is inspected, and a class whose subclasses declare the method without declaring it itself is refused.
Stored global console values and detached output methods retain identity and accept ordinary arguments.
Stored methods do not support format specifiers with substitution arguments.
Other stored console APIs, custom Console instances, and console mutation are unsupported.
JavaScript and TypeScript can store process.stdin, stdout, and stderr, replace output write methods, and call saved methods with their stream receiver.
A replaced write method does not receive console's error-callback argument.
Input supports data/end/error listeners, pause/resume, buffered reads, and TTY raw mode.
Output writes are synchronous, with successful callbacks on the next-tick queue; queued backpressure is not modeled.
Because no write is ever queued, writableLength is 0, writableNeedDrain is false, writableHighWaterMark is 65536, and 'drain' never fires, so drain listeners register silently and events.once(process.stdout, "drain") stays pending, as it does in Node when no write returned false.
Stored streams do not support piping, encoding changes, arbitrary properties, or other events.
A TypeScript NodeJS.WritableStream parameter that only receives process.stdout or process.stderr supports write(string).
When other streams flow into the same parameter, the process streams join them as Writable instances with the full writable surface.
graceful-fs
The graceful-fs package compiles as node:fs.
Its imports and require("graceful-fs") calls resolve to the builtin module, so the package's JavaScript is not compiled, and gracefulify(fs) as a statement does nothing.
Programs behave as with the package except under file-descriptor exhaustion: graceful-fs queues operations that fail with EMFILE or ENFILE and retries them when a descriptor closes, while a compiled program reports the error to its caller, as fs does.
In a compiled program, require("graceful-fs") === require("fs") is true.
DNS lookup errors
After a failed dns.lookup or dns.lookupService, Node calls the callback with the error alone, so the address and family parameters are undefined.
A callback whose address parameter is typed string (as Node's own type declarations type it) receives "" and NaN there, or an empty array for all: true, because a typed string or number cannot hold undefined.
An untyped callback receives the error alone, as in Node.
The promise forms in node:dns/promises (also reached as dns.promises) reject with the error and are unaffected.
Socket data encoding
After socket.setEncoding(), an inline 'data' listener receives strings, as in Node, whatever type its chunk parameter declares.
A listener passed by reference, such as a named function whose parameter is typed Buffer, keeps its Buffer parameter, so a string chunk throws TypeError: expected Uint8Array at $[0], got string.
Declare that parameter as string or string | Buffer, or pass an inline function.
UDP socket options
socket.addMembership() and socket.dropMembership() on a dgram socket that is not bound yet throw SC2020; Node binds such a socket to an ephemeral port first, so bind the socket before joining a group.
The SystemError that the buffer size methods throw (ERR_SOCKET_BUFFER_SIZE, for example from getRecvBufferSize() before bind()) has Node's message, code, errno and syscall, but no info object.
In JavaScript, socket.send() also accepts lists of buffers, sends on a connected socket, and takes a completion callback, which receives null and the byte count, or the send's failure instead of an 'error' event.
The callback runs after the socket's pending events, where Node runs it on the next tick.
In TypeScript, send() with a callback, a list, or on a connected socket fails to compile with SC2020.
JavaScript can read a socket's on, once, addListener, removeListener, off, emit, send, close, bind, connect, disconnect, address, ref, and unref as function values, for example socket.emit.bind(socket); reading other members as values is refused with SC1090.
Listeners registered that way, or with untyped parameters, take only the message, error, close, listening, and connect events.
When a socket closes, listeners registered from TypeScript are released, so an emit() from JavaScript after 'close' reaches only listeners registered from JavaScript.
Unix domain sockets and request options
server.listen(path) and the socketPath option of http.request() and https.request() use Unix domain sockets on Linux and macOS.
On Windows, where Node maps these paths to named pipes, they fail with ENOTSUP.
server.address() on a server listening on a Unix socket returns the socket path, as in Node, when the result is typed string | AddressInfo | null (the @types/node declaration).
Where it is typed as the { address, family, port } record alone, which cannot hold the path, the call throws an error for such a server.
listen(path, backlog, callback) is refused at compile time; pass listen(path, callback).
When the options of http.request() come from a variable, or from an object literal that spreads one, they are read at run time with Node's validation errors.
The auth, createConnection, family, hints, insecureHTTPParser, joinDuplicateHeaders, localAddress, localPort, lookup and uniqueHeaders options then throw a runtime error when they hold a value, and so do setHost: false and setDefaultHeaders: false.
Process arguments and errors
process.argv[0] is "scriptc", process.argv[1] is the binary's path, and program arguments begin at index 2.
In programs that use node:test, a leading --test-update-snapshots argument is Node's snapshot update flag: it is kept out of process.argv and appears in process.execArgv, which is otherwise [].
process.version and process.versions.node report the Node.js release the runtime is verified against.
Uncaught exceptions print Uncaught <value> to stderr instead of Node.js's source excerpt and stack-trace block; thrown strings and numbers print their value.
Exit codes and output written before the exception are preserved.
Runtime errors expose message and Node's code as typed members.
The other own properties Node gives them, such as a system error's errno, syscall, and path, a child process error's status, stdout, and stderr, or an assertion error's actual and expected, are readable through an untyped view of the error (for example a cast of a caught value) and appear in util.inspect output.
Errors carry stack frames that name the function and the source file, without Node.js's file:line:column positions or internal frames.
console.log, util.format, and util.inspect print an Error from its stack the way Node.js does: the frames under the name: message heading, brackets when the stack has no frame line, and a subclass's header named after its class (for example Bailable [Error]: message).
Only the frames themselves diverge, so the output agrees with Node.js when Error.stackTraceLimit is 0.
Module path globals
__dirname and __filename are compile-time constants: the absolute path of the module's source directory and file at build time, the same strings as import.meta.dirname and import.meta.filename.
A .ts or .tsx file keeps them even when it uses import syntax, which Node.js would load as an ES module without these globals, because TypeScript projects are commonly shipped as CommonJS bundles where they exist.
In such a file typeof __dirname is "string", where Node.js running the source directly reports "undefined".
JavaScript ES modules (.mjs, or .js in a "type": "module" package) do not have them, as in Node.js.
Runtime code evaluation
A compiled program embeds no JavaScript engine, so it cannot run JavaScript source at runtime.
eval, indirect eval, new Function, and Function behave as they do under node --disallow-code-generation-from-strings, a deliberate difference from default Node.js: every call throws a catchable EvalError with the message Code generation from strings disallowed for this context.
The arguments are evaluated first, and the Function constructor converts them to strings before it throws, as Node.js does.
Packages that test for code generation before using it, such as zod 4, take their interpreted path.
Code that needs to evaluate source at runtime must be rewritten; to compute a value from code at build time, use comptime.
The vm module is refused for the same reason.
See npm Dependencies for which packages compile.
Process events
Static signal listeners resolve names on the target platform, including SIGWINCH on POSIX.
on, once, off, and removeListener accept computed signal names and deliver the signal name and number.
Computed names for other event families and chained registrations are unsupported.
Windows registration is limited to CRT signals; WASI has no OS signals.
Literal uncaughtException and uncaughtExceptionMonitor registrations compile.
Handled exceptions resume queued native work; monitors alone do not suppress failure.
Error objects and primitive exceptions can reach listeners, while arbitrary native objects remain subject to exception-value restrictions.
Exception capture callbacks are unsupported.
Native addons
Node-API (N-API) and V8 .node addons depend on Node.js itself, so compiled programs can't load them.
Direct createRequire calls to local addons are rejected at compile time.
A package that requires an addon needs a JavaScript implementation that compiles, or a replacement through native FFI.
A package that looks for an optional addon at run time compiles with --npm-static.
In JavaScript dependencies, a createRequire require call with a computed specifier, and require.resolve called with a computed request or read as a value, resolve the specifier with the Node.js algorithm when the program runs.
require.resolve returns the path Node.js returns.
When nothing resolves, both throw the MODULE_NOT_FOUND error that Node.js throws, so a package that probes for a missing addon takes the same branch as in Node.js.
When the specifier of a require call resolves to a native addon, a builtin, or a file that is not part of the compiled program, the program prints an SC2020 error that names it and exits with status 1, because Node.js would load that module.
A catch clause around the call does not run in that case.
Resolution steps that the runtime does not reproduce, such as package imports specifiers, require.resolve options, and subpaths that a package does not export, end the program the same way.
Coverage lists these calls as deferred to runtime.
Other computed uses compile when they are inside a try block: a require call with spread arguments, a require.resolve call with another argument count, and require.resolve.paths called with a computed request evaluate their arguments and then throw an error, and require.resolve.paths read as a value is a function that throws when called.
Coverage lists these as deferred to runtime as well, and the package's catch clause then runs as it does in Node.js when the addon is missing.
Outside a try block, these uses keep the package refused.
This applies until compiled programs can load addons through Node.js.
Use Native FFI to call a plain C ABI function linked from an object or static archive. The guide includes a replacement for a small Node-API helper.
WebAssembly modules
scriptc translates WebAssembly modules to native code when it builds the program; there is no interpreter or JIT in the executable.
A build translates every module whose bytes it can see: files at paths the compiler resolves (require.resolve, createRequire(...).resolve, import.meta.resolve, new URL("./x.wasm", import.meta.url), path.join(__dirname, ...)), including .so WebAssembly shared libraries such as quickjs-wasi's extensions, modules inlined as base64 or byte-array literals, .wasm files shipped by packages whose code uses WebAssembly, and files listed in a scriptc.wasm array in package.json.
At run time WebAssembly.compile, instantiate, validate and new WebAssembly.Module find the translated module by the SHA-256 of the bytes they are given.
Bytes the build did not see, including bytes produced at run time, reject with a CompileError that says the module was not translated, and WebAssembly.validate answers false for them.
scriptc coverage lists the modules a build finds, with their size, whether they validate, and the WebAssembly proposals they use.
Translated modules can use the WebAssembly 2.0 feature set: the MVP plus sign-extension operators, non-trapping float-to-int conversions, bulk memory, multi-value, mutable globals, reference types, and extended constant expressions.
Modules that use SIMD, threads, exception handling, tail calls, typed function references or GC, memory64, or multiple memories are not translated, so loading them rejects with a CompileError that names the proposal the module uses, and WebAssembly.validate answers false for them; packages that fall back to a scalar build when that happens, such as undici and es-module-lexer, take their fallback.
Invalid modules the build finds reject with a CompileError that includes the validation error.
Supported: WebAssembly.compile, instantiate (with bytes or a Module), validate, new WebAssembly.Module, new WebAssembly.Instance, new WebAssembly.Memory, new WebAssembly.Table, new WebAssembly.Global, WebAssembly.Module.imports, exports and customSections, and instanceof for every class; the error classes CompileError, LinkError and RuntimeError, constructed with or without new; globalThis.WebAssembly and its compile, instantiate and validate functions as values.
Instances expose exported functions, memories (buffer, grow), tables (get, set, grow, length) and globals (value, valueOf).
Imports can be functions, numbers or BigInts for immutable globals, and memories, tables and globals that the program constructs or other instances export; their limits, types and mutability are checked with Node.js's LinkError messages.
Function references from a table or global reach JavaScript as callable functions, and exported functions can be stored in tables and globals, which is what dynamic linkers such as quickjs-wasi's extension loader do.
Traps throw WebAssembly.RuntimeError with Node.js's messages, unbounded recursion throws RangeError, and an exception thrown by an imported function propagates through the WebAssembly frames unchanged.
A WebAssembly.Module can be sent to a worker through workerData or postMessage.
Not supported yet: the Tag and Exception constructors, shared memories (new WebAssembly.Memory({ shared: true, ... }) throws a TypeError), compileStreaming and instantiateStreaming, and the classes used as values other than with new, instanceof and WebAssembly.Module's static functions.
TypeScript sources fail to build with SC2020 at each such use, and JavaScript sources throw that diagnostic when the statement runs.
Programs built for wasm32-wasi can't use the WebAssembly API.
Differences from Node.js:
- Growing a memory, from JavaScript or inside the module, does not detach the previous
ArrayBuffer. The memory never moves, so views created before the growth stay valid but keep their old length; code that readsmemory.bufferagain after growing, as WebAssembly glue code does, behaves as in Node.js. valueOf()answers aWebAssembly.Global's value only when the receiver's static type isWebAssembly.Global; through an untyped value it answers the object, and converting aGlobalto a primitive uses the object rather than its value.- Instances are never freed, together with their memories, imports and exports.
- A load whose result the module never uses may be removed instead of trapping when its address is out of bounds. Loads whose result is dropped explicitly still trap.
- NaN payloads may differ, for example when a signaling NaN passes through arithmetic or a JavaScript number.
WebAssembly.compileandinstantiatewith bytes settle after the current microtasks, as in Node.js, but can settle aftersetImmediatecallbacks that Node.js would run later.- The executable reads
.wasmfiles at run time from the paths they had when it was built.
WASI target
The wasm32-wasi executable target supports async/await, promises, generators, timers, portable event-loop work, stdin/readline, filesystem callbacks and promises.
WASI Preview 1 does not provide sockets, process spawning, OS signals, network interfaces, or filesystem notifications.
Networking/fetch, child processes, signal APIs, os.networkInterfaces(), the os host facts without a WASI equivalent (cpus(), hostname(), freemem(), loadavg(), uptime(), getPriority()), and fs.watch are rejected before linking with SC3002.
--sanitize and native FFI are unavailable.
Library mode emits an async-free Wasm reactor with named host imports.
Native runtime localization and thread instances are unsupported.
Each Wasm instance owns independent state.
Filesystem access is limited to directories opened by the host; scriptc run exposes the current working directory and /tmp.
See Platform Support for build and run details.
Tooling and native FFI
scriptc run does not forward extra CLI arguments to the program.
Build an executable and invoke it directly to pass arguments.
Native FFI links C functions declared in a manifest. Formats 2–5 support call-scoped callbacks, copied string/byte callback parameters, explicitly released retained callbacks, and asynchronous foreign-thread delivery. Format 6 adds single-precision floats, signed 8-bit and signed/unsigned 16-bit integers, and borrowed writable byte spans. Variadic calls, structs by value, owned pointer/string/byte returns, runtime dynamic-library loading, and library-mode builds are unsupported. See Native FFI.
Numbers follow JavaScript's double-precision semantics.
Browser embedding
Wasm reactors require a host-provided WASI Preview 1 adapter. A reactor can run supported three.js CPU operations and send animated geometry, material state, and resource lifecycle notifications to an external web application through declared imports. The application supplies DOM, graphics, media, audio, and decoder bindings, including the renderer.
Library mode excludes promises, async functions, timers. See WebAssembly Modules for the embedding contract.
Native debugging
Executable builds with --optimization=dev support source breakpoints and native stack frames for compiled TypeScript and JavaScript.
LLVM builds include source names and lexical scopes for locals, parameters, captured bindings, and module globals.
Release builds and builds with --strip omit these source mappings.
On macOS, executable builds produce an adjacent .dSYM bundle using the Command Line Tools' dsymutil.
Debugger values use native representations.
Numbers and booleans display directly.
Strings expose their ScrStr layout, including UTF-8 data and byte len; tagged unions expose their tag and slot fields.
Other heap values and scalar bindings captured before initialization can appear as opaque pointers.
Debuggers can't evaluate TypeScript expressions or format values as JavaScript objects.