Hello TJS

Types-by-example: the value IS the type annotation

Types by Example

In TJS, the example value after : IS the type:

Syntax Type
name: 'Alice' string (required)
count: 42 integer
rate: 3.14 number (float)
index: +0 non-negative integer
name = 'default' string (optional, defaults to 'default')
data: { x: 0, y: 0 } object with shape
...nums: [0] rest param, array of integers
/**
 * But **jsDoc** is also supported.
 */

function greet(name: 'World'): 'Hello, World!' {
  return `Hello, ${name}!`
}

// Numeric type narrowing — all valid JS syntax
function clampIndex(index: +0, max: +0): +0 {
  return Math.min(index, max)
}

function mix(a: 0.0, b: 0.0, t: 0.0): 0.0 {
  return a + (b - a) * t
}

test 'greet says hello' {
  expect(greet('TJS')).toBe('Hello, TJS!')
}

test 'type errors are values, not exceptions' {
  const err = greet(42)
  expect(err instanceof Error).toBe(true)
}

test 'numeric types are precise' {
  expect(clampIndex(5, 10)).toBe(5)
  // negative fails non-negative integer check
  expect(clampIndex(-1, 10) instanceof Error).toBe(true)
  // float fails integer check
  expect(clampIndex(3.5, 10) instanceof Error).toBe(true)
}

test 'floats accept any number' {
  expect(mix(0, 100, 0.5)).toBe(50)
}

// Rest params — the array example IS the type
function sum(...nums: [1, 2, 3]): 6 {
  return nums.reduce((a = 0, b: 0) => a + b, 0)
}

function mean(...values: [1.0, 2.0, 3.0, 2.0]): 2.0 {
  return values.length
    ? values.reduce((sum = 0.0, x: 1.0) => sum + x) / values.length
    : 0.0
}

test 'sum integers' {
  expect(sum(1, 2, 3)).toBe(6)
}

test 'mean of floats' {
  expect(mean(10, 20, 30)).toBe(20)
}

test 'mean of empty' {
  expect(mean()).toBe(0)
}