Examples
Practical SJS examples organized by category. Every example uses valid SJS syntax and can be compiled with superjs build.
1. Basics
Hello World
// hello-world.sjs
const message: string = "Hello, World!"
console.log(message)
function greet(name: string): string {
return `Hello, ${name}!`
}
console.log(greet("Super.js"))Variables and Type Annotations
// variables.sjs
const count: number = 42
const label: string = "items"
const active: boolean = true
// Type inference — annotation optional when value is clear
const ratio = 0.75 // inferred: number
const title = "SuperJS" // inferred: string
console.log(`${count} ${label}`)Functions
// functions.sjs
function add(a: number, b: number): number {
return a + b
}
function repeat(text: string, times: number): string {
return text.repeat(times)
}
const double = (n: number): number => n * 2
console.log(add(3, 4)) // 7
console.log(repeat("ha", 3)) // hahaha
console.log(double(10)) // 202. Null Safety
SJS types are non-nullable by default. Append ? to allow null or undefined.
// null-safety.sjs
function findUser(id: number): string? {
if (id === 1) return "Alice"
return null
}
const name = findUser(42) // type: string?
const display = name ?? "Unknown"
console.log(display) // "Unknown"Optional Chaining and Nullish Coalescing
type Address {
street: string
city: string
zip: string?
}
type User {
name: string
address: Address?
}
function getZip(user: User): string {
return user.address?.zip ?? "N/A"
}Nullable Return Types
function parseInt10(s: string): number? {
const n = parseInt(s, 10)
return isNaN(n) ? null : n
}
const result = parseInt10("abc")
if (result !== null) {
console.log(result * 2)
}3. Sum Types and Match
Sum types declare a closed set of variants. The match expression handles each variant and the compiler enforces exhaustiveness (SJS-E007).
Result Type
// result.sjs
type Result<T, E> = Ok(T) | Err(E)
function divide(a: number, b: number): Result<number, string> {
if (b === 0) return Err("division by zero")
return Ok(a / b)
}
const r = divide(10, 2)
const msg = match r {
Ok(val) => `Result: ${val}`,
Err(e) => `Error: ${e}`,
}
console.log(msg) // "Result: 5"Option Type
// option.sjs
type Option<T> = Some(T) | None
function head<T>(arr: T[]): Option<T> {
return arr.length > 0 ? Some(arr[0]) : None
}
const first = head([10, 20, 30])
const display = match first {
Some(v) => `First: ${v}`,
None => "Empty list",
}
console.log(display) // "First: 10"Exhaustiveness Checking
Missing a variant produces a SJS-E007 error at compile time:
type Color = Red | Green | Blue
function label(c: Color): string {
return match c {
Red => "red",
Green => "green",
Blue => "blue",
}
}4. Generics
Generic Stack
// stack.sjs
class Stack<T> {
private items: T[] = []
push(item: T): void { this.items.push(item) }
pop(): T? {
if (this.items.length === 0) return null
return this.items.pop() ?? null
}
peek(): T? {
return this.items.length > 0 ? this.items[this.items.length - 1] : null
}
get size(): number { return this.items.length }
}
const stack = new Stack<number>()
stack.push(1)
stack.push(2)
stack.push(3)
console.log(stack.pop()) // 3
console.log(stack.size) // 2Generic Functions
function identity<T>(value: T): T {
return value
}
function first<T>(arr: T[]): T? {
return arr.length > 0 ? arr[0] : null
}
function zip<A, B>(as: A[], bs: B[]): [A, B][] {
const len = Math.min(as.length, bs.length)
const result: [A, B][] = []
for (let i = 0; i < len; i++) {
result.push([as[i], bs[i]])
}
return result
}
console.log(zip([1, 2, 3], ["a", "b", "c"]))
// [[1, "a"], [2, "b"], [3, "c"]]5. Structural Object Types
SJS object types are structural — a class satisfies an object type by having the right shape, no implements keyword required. Object types use the brace form of type (no =).
type Shape {
area(): number
perimeter(): number
}
class Circle {
constructor(private radius: number) {}
area(): number {
return Math.PI * this.radius ** 2
}
perimeter(): number {
return 2 * Math.PI * this.radius
}
}
class Rectangle {
constructor(private width: number, private height: number) {}
area(): number {
return this.width * this.height
}
perimeter(): number {
return 2 * (this.width + this.height)
}
}
function describe(s: Shape): string {
return `area=${s.area().toFixed(2)}, perimeter=${s.perimeter().toFixed(2)}`
}
console.log(describe(new Circle(5)))
console.log(describe(new Rectangle(4, 6)))Object Type Composition
type Named {
name: string
}
type Aged {
age: number
}
type Person extends Named, Aged {
email: string
}
function greet(p: Person): string {
return `Hello, ${p.name} (age ${p.age})`
}6. JSX
JSX is enabled by default in SJS. Use it directly in .sjs files with no extra configuration.
Typed Props
// card.sjs
type CardProps {
title: string
body: string
footer?: string
}
function Card({ title, body, footer }: CardProps) {
return (
<div className="card">
<h2>{title}</h2>
<p>{body}</p>
{footer && <footer>{footer}</footer>}
</div>
)
}Component with Event Handlers
type ButtonProps {
label: string
onClick: () => void
disabled?: boolean
}
function Button({ label, onClick, disabled = false }: ButtonProps) {
return (
<button
className={disabled ? "btn btn-disabled" : "btn"}
onClick={onClick}
disabled={disabled}
>
{label}
</button>
)
}List Rendering
type ListProps {
items: string[]
emptyMessage?: string
}
function List({ items, emptyMessage = "Nothing here." }: ListProps) {
if (items.length === 0) {
return <p>{emptyMessage}</p>
}
return (
<ul>
{items.map((item, i) => (
<li key={i}>{item}</li>
))}
</ul>
)
}7. Node.js Usage
File Analysis CLI Tool
// analyze.sjs
import fs from 'fs'
import path from 'path'
type FileStats {
path: string
lines: number
sizeBytes: number
}
type AnalysisResult<T> = Success(T) | Failure(string)
function analyzeFile(filePath: string): AnalysisResult<FileStats> {
try {
const content = fs.readFileSync(filePath, 'utf-8')
return Success({
path: filePath,
lines: content.split('\n').length,
sizeBytes: Buffer.byteLength(content),
})
} catch (e) {
return Failure(`Cannot read ${filePath}`)
}
}
const result = analyzeFile(process.argv[2])
match result {
Success(stats) => console.log(`${stats.lines} lines, ${stats.sizeBytes} bytes`),
Failure(msg) => console.error(msg),
}Directory Walker
// walk.sjs
import fs from 'fs'
import path from 'path'
function walkDir(dir: string): string[] {
const entries = fs.readdirSync(dir, { withFileTypes: true })
const files: string[] = []
for (const entry of entries) {
const full = path.join(dir, entry.name)
if (entry.isDirectory()) {
files.push(...walkDir(full))
} else {
files.push(full)
}
}
return files
}
const target = process.argv[2] ?? "."
const files = walkDir(target)
console.log(`Found ${files.length} files`)
files.forEach(f => console.log(f))HTTP Server
// server.sjs
import http from 'http'
type Route {
method: string
path: string
handler: (body: string) => string
}
const routes: Route[] = [
{
method: "GET",
path: "/",
handler: () => JSON.stringify({ message: "Hello from SJS!" }),
},
]
const server = http.createServer((req, res) => {
const route = routes.find(
r => r.method === req.method && r.path === req.url
)
if (!route) {
res.writeHead(404)
res.end(JSON.stringify({ error: "Not found" }))
return
}
let body = ""
req.on("data", chunk => { body += chunk })
req.on("end", () => {
res.writeHead(200, { "Content-Type": "application/json" })
res.end(route.handler(body))
})
})
server.listen(3000, () => console.log("Listening on :3000"))