Awesome
TypeScript Native Compiler
Powered by
Build
What's new
- Public, private, and protected modifiers
class Point {
private x: number;
#y: number;
}
const p = new Point();
p.x // access error
p.#y // error
- Class from Tuple
class Point {
x: number;
y: number;
}
class Line {
constructor(public start: Point, public end: Point) { }
}
const l = new Line({ x: 0, y: 1 }, { x: 1.0, y: 2.0 });
- Compile-time
if
s
function isArray<T extends unknown[]>(value: T): value is T {
return true;
}
function gen<T>(t: T)
{
if (isArray(t))
{
return t.length.toString();
}
return "int";
}
const v1 = gen<i32>(23); // result: int
const v2 = gen<string[]>([]); // result: 0
- indexes for classes and interfaces, properties for interfaces
class Test {
// declare index (to assigning get/set methods to it)
[index1: number]: string;
get(index: number): string {
return "index";
}
set(index: number, value: string) {
}
get val(): string {
return "prop";
}
}
interface ITest {
[index1: number]: string;
get val(): string;
}
const t = new Test();
print(t[10]);
const ti: ITest = t;
print(ti[10]);
print(ti.val);
- no need to define 'main' function
const arr = [1, 2, 3, 4, 5];
for (const b of arr)
print(b);
- Accessor for object fields
let obj = {
p: 1.0,
get value() { return this.p; },
set value(v: number) { this.p = v; },
}
- Class static block
class C {
static x: number;
static {
C.x = 1;
}
}
-
Migrated to LLVM 19.1.3
-
improved
generating debug information
more info here: Wiki:How-To
tsc --di --opt_level=0 --emit=exe example.ts
- cast from Union Types
let a: string | number = 5;
let b: string = a; // b is "5"
- All functions without types are generics
static class Array {
public of(...arg) {
return arg;
}
public from(arrayLike) {
return [...arrayLike];
}
}
- Native types aliases
// byte, short, ushort, int, uint, long, ulong, char, i8, i16, i32, i64,
// u8, u16, u32, u64, s8, s16, s32, s64, f16, f32, f64, f128, half, float, double, index
const s1: s8 = -1;
const s2: u16 = 2;
const s3: i32 = 3;
const s4: f64 = 1.0;
- Reference types (aka pointers)
let a = [1, 2, 3];
const view: Reference<TypeOf<1>> = ReferenceOf(a[1]);
const data = LoadReference(view);
const data1 = LoadReference(view[1]);
- Accessor
class Person {
static accessor sname: string;
accessor name = "no value";
constructor(name: string) {
this.name = name;
}
}
- Explicit Resource Management
function main()
{
using file = new TempFile(".some_temp_file");
print("done.");
}
class TempFile {
#path: string;
#handle: number;
constructor(path: string) {
this.#path = path;
this.#handle = 1;
}
// other methods
[Symbol.dispose]() {
// Close the file and delete it.
this.#handle = 0;
print("dispose");
}
}
Planning
- Migrating to LLVM 19.1.3
- Shared libraries
- JavaScript Built-in classes library
Demo
Try it
Chat Room
Want to chat with other members of the TypeScriptCompiler community?
Example
abstract class Department {
constructor(public name: string) {}
printName(): void {
print("Department name: " + this.name);
}
abstract printMeeting(): void; // must be implemented in derived classes
}
class AccountingDepartment extends Department {
constructor() {
super("Accounting and Auditing"); // constructors in derived classes must call super()
}
printMeeting(): void {
print("The Accounting Department meets each Monday at 10am.");
}
generateReports(): void {
print("Generating accounting reports...");
}
}
function main() {
let department: Department; // ok to create a reference to an abstract type
department = new AccountingDepartment(); // ok to create and assign a non-abstract subclass
department.printName();
department.printMeeting();
//department.generateReports(); // error: department is not of type AccountingDepartment, cannot access generateReports
}
Run
tsc --emit=jit --opt --shared-libs=TypeScriptRuntime.dll example.ts
Result
Department name: Accounting and Auditing
The Accounting Department meets each Monday at 10am.
Run as JIT
- with Garbage collection
tsc --emit=jit --opt --shared-libs=TypeScriptRuntime.dll hello.ts
- without Garbage collection
tsc --emit=jit --nogc hello.ts
File hello.ts
function main() {
print("Hello World!");
}
Result
Hello World!
Compile as Binary Executable
On Windows
File tsc-compile.bat
set FILENAME=%1
set GC_LIB_PATH=C:\dev\TypeScriptCompiler\__build\gc\msbuild\x64\release\Release
set LLVM_LIB_PATH=C:\dev\TypeScriptCompiler\__build\llvm\msbuild\x64\release\Release\lib
set TSC_LIB_PATH=C:\dev\TypeScriptCompiler\__build\tsc\windows-msbuild-release\lib
set TSCEXEPATH=C:\dev\TypeScriptCompiler\__build\tsc\windows-msbuild-release\bin
%TSCEXEPATH%\tsc.exe --opt --emit=exe %FILENAME%.ts
Compile
tsc-compile.bat hello
Run
hello.exe
Result
Hello World!
On Linux (Ubuntu 20.04 and 22.04)
File tsc-compile.sh
FILENAME=$1
export TSC_LIB_PATH=~/dev/TypeScriptCompiler/__build/tsc/linux-ninja-gcc-release/lib
export LLVM_LIB_PATH=~/dev/TypeScriptCompiler/3rdParty/llvm/release/lib
export GC_LIB_PATH=~/dev/TypeScriptCompiler/3rdParty/gc/release
TSCEXEPATH=~/dev/TypeScriptCompiler/__build/tsc/linux-ninja-gcc-release/bin
$TSCEXEPATH/tsc --emit=exe $FILENAME.ts --relocation-model=pic
Compile
sh -f tsc-compile.sh hello
Run
./hello
Result
Hello World!
Compiling as WASM
On Windows
File tsc-compile-wasm.bat
set FILENAME=%1
set GC_LIB_PATH=C:\dev\TypeScriptCompiler\__build\gc\msbuild\x64\release\Release
set LLVM_LIB_PATH=C:\dev\TypeScriptCompiler\__build\llvm\msbuild\x64\release\Release\lib
set TSC_LIB_PATH=C:\dev\TypeScriptCompiler\__build\tsc\windows-msbuild-release\lib
C:\dev\TypeScriptCompiler\__build\tsc\windows-msbuild-release\bin\tsc.exe --emit=exe --nogc -mtriple=wasm32-unknown-unknown %FILENAME%.ts
Compile
tsc-compile-wasm.bat hello
Run run.html
<!DOCTYPE html>
<html>
<head></head>
<body>
<script type="module">
let buffer;
let buffer32;
let buffer64;
let bufferF64;
let heap;
let heap_base, heap_end, stack_low, stack_high;
const allocated = [];
const allocatedSize = (addr) => {
return allocated["" + addr];
};
const setAllocatedSize = (addr, newSize) => {
allocated["" + addr] = newSize;
};
const expand = (addr, newSize) => {
const aligned_newSize = newSize + (4 - (newSize % 4))
const end = addr + allocatedSize(addr);
const newEnd = addr + aligned_newSize;
for (const allocatedAddr in allocated) {
const beginAllocatedAddr = parseInt(allocatedAddr);
const endAllocatedAddr = beginAllocatedAddr + allocated[allocatedAddr];
if (beginAllocatedAddr != addr && addr < endAllocatedAddr && newEnd > beginAllocatedAddr) {
return false;
}
}
setAllocatedSize(addr, aligned_newSize);
if (addr + aligned_newSize > heap) heap = addr + aligned_newSize;
return true;
};
const endOf = (addr) => { while (buffer[addr] != 0) { addr++; if (addr > heap_end) throw "out of memory boundary"; }; return addr; };
const strOf = (addr) => String.fromCharCode(...buffer.slice(addr, endOf(addr)));
const copyStr = (dst, src) => { while (buffer[src] != 0) buffer[dst++] = buffer[src++]; buffer[dst] = 0; return dst; };
const ncopy = (dst, src, count) => { while (count-- > 0) buffer[dst++] = buffer[src++]; return dst; };
const append = (dst, src) => copyStr(endOf(dst), src);
const cmp = (addrL, addrR) => { while (buffer[addrL] != 0) { if (buffer[addrL] != buffer[addrR]) break; addrL++; addrR++; } return buffer[addrL] - buffer[addrR]; };
const prn = (str, addr) => { for (let i = 0; i < str.length; i++) buffer[addr++] = str.charCodeAt(i); buffer[addr] = 0; return addr; };
const clear = (addr, size, val) => { for (let i = 0; i < size; i++) buffer[addr++] = val; };
const aligned_alloc = (size) => {
const aligned_size = size + (4 - (size % 4));
if ((heap + aligned_size) > heap_end) throw "out of memory";
setAllocatedSize(heap, aligned_size);
const heapCurrent = heap;
heap += aligned_size;
return heapCurrent;
};
const free = (addr) => delete allocated["" + addr];
const realloc = (addr, size) => {
if (!expand(addr, size)) {
const newAddr = aligned_alloc(size);
ncopy(newAddr, addr, allocatedSize(addr));
free(addr);
return newAddr;
}
return addr;
}
const envObj = {
memory: new WebAssembly.Memory({ initial: 256 }),
table: new WebAssembly.Table({
initial: 0,
element: 'anyfunc',
}),
fmod: (arg1, arg2) => arg1 % arg2,
sqrt: (arg1) => Math.sqrt(arg1),
floor: (arg1) => Math.floor(arg1),
pow: (arg1, arg2) => Math.pow(arg1, arg2),
fabs: (arg1) => Math.abs(arg1),
_assert: (msg, file, line) => console.assert(false, strOf(msg), "| file:", strOf(file), "| line:", line, " DBG:", path),
puts: (arg) => output += strOf(arg) + '\n',
strcpy: copyStr,
strcat: append,
strcmp: cmp,
strlen: (addr) => endOf(addr) - addr,
malloc: aligned_alloc,
realloc: realloc,
free: free,
memset: (addr, size, val) => clear(addr, size, val),
atoi: (addr, rdx) => parseInt(strOf(addr), rdx),
atof: (addr) => parseFloat(strOf(addr)),
sprintf_s: (addr, sizeOfBuffer, format, ...args) => {
const formatStr = strOf(format);
switch (formatStr) {
case "%d": prn(buffer32[args[0] >> 2].toString(), addr); break;
case "%g": prn(bufferF64[args[0] >> 3].toString(), addr); break;
case "%llu": prn(buffer64[args[0] >> 3].toString(), addr); break;
default: throw "not implemented";
}
return 0;
},
}
const config = {
env: envObj,
};
WebAssembly.instantiateStreaming(fetch("./hello.wasm"), config)
.then(results => {
const { main, __wasm_call_ctors, __heap_base, __heap_end, __stack_low, __stack_high } = results.instance.exports;
buffer = new Uint8Array(results.instance.exports.memory.buffer);
buffer32 = new Uint32Array(results.instance.exports.memory.buffer);
buffer64 = new BigUint64Array(results.instance.exports.memory.buffer);
bufferF64 = new Float64Array(results.instance.exports.memory.buffer);
heap = heap_base = __heap_base, heap_end = __heap_end, stack_low = __stack_low, stack_high = __stack_high;
try
{
if (__wasm_call_ctors) __wasm_call_ctors();
main();
}
catch (e)
{
console.error(e);
}
});
</script>
</body>
</html>
Build
On Windows
Requirements:
Visual Studio 2022
- 512GB of free space on disk
First, precompile dependencies
cd TypeScriptCompiler
prepare_3rdParty.bat
To build TSC
binaries:
cd TypeScriptCompiler\tsc
config_tsc_release.bat
build_tsc_release.bat
On Linux (Ubuntu 20.04 and 22.04)
Requirements:
GCC
orClang
- 512GB of free space on disk
- sudo apt-get install
libtinfo-dev
First, precompile dependencies
chmod +x *.sh
cd ~/TypeScriptCompiler
./prepare_3rdParty.sh
To build TSC
binaries:
cd ~/TypeScriptCompiler/tsc
chmod +x *.sh
./config_tsc_release.sh
./build_tsc_release.sh