Integer character literals
Single quotes hold exactly one Unicode code point and compile directly to an integer in JavaScript and C++. Double quotes remain strings.
val letter: int = 'a'
val emoji: int = '๐'
val matches = "aaa".charCodeAt(0) == 'a'
Primary-constructor classes
Declare class members directly in the constructor signature. val for read-only, var for mutable. No boilerplate.
class User(val id: string, var name: string, val score: int = 0)
val u = User("u1", "Alice")
u.name = "Bob"
Operator overloading
Define arithmetic, comparison, and index operators directly on your types. Shorthand arrow syntax keeps definitions terse.
class Vec2(val x: number, val y: number) {
operator+(b: Vec2) => Vec2(x + b.x, y + b.y)
operator*(s: number) => Vec2(x * s, y * s)
length => Math.hypot(x, y)
}
val v = Vec2(1, 0) + Vec2(0, 1) * 3
Await-less async
sync fun automatically awaits any Promise produced inside the body. Write async logic that reads like sync code โ no await keywords needed.
sync fun loadBytes(url: string): Uint8Array {
val res = fetch(url)
return Uint8Array(res.arrayBuffer())
}
Delegated variables
Kotlin-style by delegates let you attach custom read/write behaviour to any variable. Works with React-style state tuples out of the box.
fun useState(init: number) {
return [() => init, (v: number) => { init = v }]
}
var count by useState(0)
count++
console.log(count)
Null-aware access
Optional chaining and nullish coalescing are fully supported. Non-null assertions let you opt out of null checks when you know better.
val city = user.address?.city ?? "Unknown"
val label = maybeUser!.name.toUpperCase()
New-less instantiation
Call constructors without new. Classes and built-ins like Map, Set, and Uint8Array work the same way.
val users = Map<string, User>()
val buf = Uint8Array(1024)
val pt = Point(3, 4)
JavaScript and native C++
The same analyzed project can emit JavaScript, a C++ translation unit, or an optimized native executable. TypeScript entrypoints are supported too.
vexa build app.ts -o app.js
vexa cpp app.ts -o app.cpp
vexa cpp link app.ts -o app
Cross-backend FFI
@FFILibrary, ABI-aware structs, pointers, and buffers describe a native API once. Deno uses dynamic FFI while generated C++ calls the same symbols directly.
@FFILibrary("libSDL2.so", "SDL2.framework/SDL2")
ambient class SDL2 {
static fun SDL_Init(flags: int): int
}
A self-hosting compiler
VexaScript compiles the complete TypeScript compiler graph, then runs the generated compiler to produce the next generation in JavaScript or native C++.
pnpm self-host
vexa cpp run cli/cli.ts -o vexa-native