Skip to content

TypeScript Blocks

Vibe runs on a TypeScript runtime, allowing you to drop into TypeScript whenever needed.

let result = ts() {
return Math.random() * 100;
}

Pass Vibe variables into TypeScript:

let x = 10
let y = 20
let sum = ts(x, y) {
return x + y;
}

Variables are passed by name and available inside the block.

Use name=expr to alias a variable or access a sub-expression:

let longVariableName = "hello"
let result = ts(s=longVariableName) {
return s.toUpperCase();
}

You can pass member access, array index, and slice expressions as parameters:

// Member access
let obj: json = { name: "Alice", scores: [95, 87, 92] }
let name = ts(n=obj.name) {
return n.toUpperCase();
}
// Array index access
let items = [10, 20, 30, 40, 50]
let first = ts(x=items[0]) { return x * 2; }
let last = ts(x=items[-1]) { return x + 1; }
// Slice access
let middle = ts(sub=items[1:4]) {
return sub.reduce((a, b) => a + b, 0);
}
// Chained access
let score = ts(s=obj.scores[0]) { return s; }
let tail = ts(rest=obj.scores[1:]) {
return rest.length;
}

Supported expression patterns:

  • var.field — object member access
  • var[n] — array index (supports negative indices)
  • var[start:end] — array slice (start/end are optional)
  • var.field[n].other — chained access

Types are automatically resolved through the access chain, enabling full type checking inside the ts block.

Vibe performs compile-time type checking on ts() blocks. The types of Vibe variables are mapped to TypeScript types:

Vibe TypeTypeScript Type
textstring
numbernumber
booleanboolean
jsonRecord<string, unknown>
let x: text = "hello"
// This will error at compile time - can't multiply a string
let bad = ts(x) {
return x * 2; // Error: left-hand side must be number
}
// This is valid
let good = ts(x) {
return x.toUpperCase();
}

Vibe automatically infers the return type of ts() blocks:

let num = ts() { return 42; } // Inferred as number
let str = ts() { return "hello"; } // Inferred as text
let obj = ts() { return { a: 1 }; } // Inferred as json
// Type mismatch will error
let x: text = ts() { return 42; } // Error: cannot assign number to text
let jsonString = '{"name": "Alice", "age": 30}'
let parsed = ts(jsonString) {
const data = JSON.parse(jsonString);
return data.name.toUpperCase();
}
let items = [1, 2, 3, 4, 5]
let doubled = ts(items) {
return items.map(x => x * 2);
}
let filtered = ts(items) {
return items.filter(x => x > 2);
}
let data = ts() {
const response = await fetch('https://api.example.com/data');
return await response.json();
}

Inside ts blocks, you can use dynamic await import() for Node built-ins:

let files = ts() {
const { readdirSync } = await import('fs');
return readdirSync('.').filter(f => f.endsWith('.vibe'));
}
let fullPath = ts(filename) {
const { join } = await import('path');
return join(process.cwd(), filename);
}
let aiResponse = do "Generate a list of 5 items as JSON"
let processed = ts(aiResponse) {
const items = JSON.parse(aiResponse);
return items
.filter(item => item.score > 0.8)
.map(item => item.name)
.join(", ");
}

TypeScript blocks can return any type:

// Return number
let count: number = ts() { return 42; }
// Return text
let greeting: text = ts() { return "Hello"; }
// Return array
let items: text[] = ts() { return ["a", "b", "c"]; }
// Return object
let config: json = ts() {
return { timeout: 5000, retries: 3 };
}
let result = ts(input) {
try {
return JSON.parse(input);
} catch (e) {
return { error: e.message };
}
}

TypeScript blocks are commonly used in tool implementations:

tool processData(data: json): json
@description "Process and transform data"
{
ts(data) {
return {
count: data.items.length,
total: data.items.reduce((sum, item) => sum + item.value, 0),
average: data.items.reduce((sum, item) => sum + item.value, 0) / data.items.length
};
}
}
// Good - single purpose
let parsed = ts(json) {
return JSON.parse(json);
}
// Avoid - too much logic
let result = ts(data) {
// 50 lines of complex logic...
}
// Good - Vibe doesn't have regex
let matches = ts(text) {
return text.match(/\d+/g) || [];
}
// Unnecessary - Vibe can do this
let sum = ts(a, b) { return a + b; }
// Better: let sum = a + b
let safeResult = ts(input) {
try {
return { success: true, data: riskyOperation(input) };
} catch (e) {
return { success: false, error: e.message };
}
}