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 |

Incidentally, you're looking at inline markdown docs...
#/

/**
 * 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)
}