Skip to content

typesugarSyntactic sugar for TypeScript with zero calories

Operators and methods that just work, compiled to exactly what you'd write by hand.

typesugar

Quick Example โ€‹

typescript
interface User {
  id: number;
  name: string;
  email: string;
}

const alice: User = { id: 1, name: "Alice", email: "alice@example.com" };
const bob: User = { id: 2, name: "Bob", email: "bob@example.com" };

// Operators just work โ€” auto-derived, auto-specialized
alice === bob; // Compiles to: alice.id === bob.id && alice.name === bob.name && ...
alice < bob; // Lexicographic comparison

// Methods just work too
alice.show(); // "User(id = 1, name = Alice, email = alice@example.com)"
alice.clone(); // Deep copy
alice.toJson(); // JSON serialization

How it works: The compiler sees === on a User, resolves the Eq typeclass, auto-derives an instance from the type's fields, and inlines the comparison directly โ€” no dictionary lookup, no runtime cost.


Macro System โ€‹

Custom language features that compile away

typesugar provides 6 kinds of macros, each triggered differently:

  • Expression macros โ€” myMacro(...) function calls
  • Attribute macros โ€” @myDecorator on classes, methods, properties
  • Derive macros โ€” @derive(Eq, Clone) generates implementations from type structure
  • Tagged template macros โ€” sql`SELECT * FROM users` with compile-time validation
  • Type macros โ€” Refined<number, Positive> at the type level
  • Labeled block macros โ€” let: { } yield: { } for custom control flow
typescript
// Define a simple expression macro
defineSyntaxMacro("unless", {
  arms: [
    {
      pattern: "$cond:expr, $body:expr",
      expand: "($cond) ? undefined : ($body)",
    },
  ],
});

// Use it
unless(isLoggedIn, redirect("/login"));
// Compiles to: (isLoggedIn) ? undefined : (redirect("/login"))

Writing Macros Guide ยท Macro Types Reference


Functional Programming & Type Theory โ€‹

Typeclasses, monads, and proofs โ€” for the nerds

If you're into FP, typesugar has you covered:

  • Typeclasses with implicit resolution and zero-cost specialization โ€” Eq, Ord, Show, Functor, Monad, and more
  • Data types โ€” Option (null-based, zero-cost), Either, IO, Validated, List
  • Do-notation via let:/yield: labeled blocks โ€” works with any monad
  • HKT with F<A> syntax โ€” write generic code over type constructors
  • Refined types โ€” Positive, Port, Email, NonEmpty<T> with compile-time validation
  • Design by Contract โ€” requires(), ensures(), @invariant with compile-time proof elimination
typescript
// HKT with F<A> syntax (the transformer rewrites F<A> to Kind<F, A>)
interface Functor<F> {
  map<A, B>(fa: F<A>, f: (a: A) => B): F<B>;
}

// Do-notation for any monad
const result = let: {
  user  << fetchUser(id);
  posts << fetchPosts(user.id);
  stats << computeStats(posts);
}
yield: { { user, posts, stats } };

// Contracts with compile-time proof elimination
function sqrt(x: number): number {
  requires: { x >= 0 }
  ensures: { result => result >= 0 }
  return Math.sqrt(x);
}

Typeclasses Guide ยท FP Guide ยท Contracts Guide


Compile-Time Powers โ€‹

Run code at build time, not at runtime

Move computation from runtime to compile time:

  • comptime() โ€” evaluate any expression at build time
  • @tailrec โ€” tail-call elimination for stack-safe recursion
  • includeStr() / includeJson() โ€” embed file contents at compile time
  • staticAssert() โ€” compile-time assertions that disappear in output
  • cfg() / @cfgAttr โ€” conditional compilation for feature flags
  • collectTypes() โ€” introspect your entire project at compile time
  • "use no typesugar" โ€” opt-out directives for debugging and interop
typescript
// Computed at compile time, inlined as a literal
const BUILD_TIME = comptime(new Date().toISOString());
const FIB_50 = comptime(fibonacci(50));

// Stack-safe recursion via loop transformation
@tailrec
function factorial(n: number, acc = 1): number {
  if (n <= 1) return acc;
  return factorial(n - 1, n * acc);
}
// Compiles to: while(true) { if (n <= 1) return acc; acc = n * acc; n = n - 1; }

// Embed files at compile time
const SCHEMA = includeJson("./schema.json");
const TEMPLATE = includeStr("./email.html");

Compile-Time Guide ยท Conditional Compilation


Standard Library โ€‹

TypeScript's missing standard library

Batteries included for everyday TypeScript:

  • Extension methods โ€” (42).clamp(0, 100), "hello".capitalize(), [1,2,3].sum()
  • Pattern matching โ€” exhaustive match() with discriminated unions, guards, OR patterns
  • Reflection โ€” typeInfo<T>(), fieldNames<T>(), validator<T>() at compile time
  • Object mapping โ€” transformInto() for zero-cost struct-to-struct conversion
  • Derive macros โ€” @derive(Eq, Ord, Clone, Debug, Hash, Json, Builder, TypeGuard)
  • Tagged templates โ€” sql, regex, html, fmt with compile-time validation
typescript
// Pattern matching with exhaustiveness checking
type Result<T, E> = { tag: "Ok"; value: T } | { tag: "Err"; error: E };

const message = match(result, {
  Ok: ({ value }) => `Got ${value}`,
  Err: ({ error }) => `Failed: ${error}`,
});

// Extension methods on primitives
const clamped = (255).clamp(0, 100); // 100
const words = "hello world".words(); // ["hello", "world"]
const total = [1, 2, 3, 4, 5].sum(); // 15

// Auto-derive common implementations
@derive(Eq, Clone, Debug, Json)
class Point {
  constructor(
    public x: number,
    public y: number
  ) {}
}

Pattern Matching ยท Derive Guide ยท Extension Methods


Data Structures & Algorithms โ€‹

Powerful abstractions with zero runtime cost

Advanced data structures and algorithms following typesugar's zero-cost philosophy:

  • HList โ€” Heterogeneous lists with compile-time type tracking (Boost.Fusion)
  • Parser โ€” Compile-time parser generation from PEG grammars (Boost.Spirit)
  • Fusion โ€” Single-pass iterator pipelines and expression templates (Blitz++)
  • Graph โ€” Graph algorithms and state machine verification (Boost.Graph)
  • Erased โ€” Typeclass-based type erasure for heterogeneous collections (dyn Trait)
  • Codec โ€” Versioned serialization with schema evolution (Boost.Serialization)
typescript
// Lazy iterator fusion โ€” single pass, no intermediate arrays
const result = lazy([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
  .filter((x) => x % 2 === 0)
  .map((x) => x * x)
  .take(3)
  .toArray();
// โ†’ [4, 16, 36] โ€” single loop, early termination

// PEG grammar โ†’ recursive descent parser
const csv = grammar`
  file   = record ("\\n" record)*
  record = field ("," field)*
  field  = quoted | unquoted
  quoted = '"' (!'"' .)* '"'
  unquoted = (!',' !'\\n' .)*
`;

HList Guide ยท Parser Guide ยท Fusion Guide ยท Graph Guide


Framework Adapters โ€‹

Supercharge your existing tools

typesugar integrates deeply with popular frameworks:

Effect-TS โ€‹

Reduce Effect boilerplate with macros. The let:/yield: do-notation works seamlessly with Effect.

typescript
@service
class UserService {
  getUser(id: string) { return Effect.succeed({ id, name: "Alice" }); }
}

@layer
class UserServiceLive implements UserService {
  getUser(id: string) { return Effect.succeed({ id, name: "Alice" }); }
}

// Do-notation with Effect
const program = let: {
  user  << UserService.getUser("123");
  posts << PostService.getPosts(user.id);
}
yield: { posts.length };

Testing โ€‹

Power assertions and property-based testing:

typescript
// Power assertions show expression breakdown on failure
assert(user.age > 18 && user.name.length > 0);
// On failure:
//   assert(user.age > 18 && user.name.length > 0)
//          |    |   |     |    |    |      |
//          |    16  false |    ""   0      false
//          { age: 16, name: "" }

class Point {
  constructor(
    public x: number,
    public y: number
  ) {}
}

// forAll auto-derives Arbitrary generators from field types
forAll(Point, (p) => p.x + p.y === p.y + p.x);
forAll(Point, 1000, (p) => p.x * 0 === 0); // custom iteration count

Effect Integration ยท Testing Guide


Developer Experience โ€‹

When something goes wrong, you should know exactly what happened and how to fix it.

Rust-Style Errors โ€‹

Every error shows the code, points at the problem, and suggests a fix:

error[TS9101]: Cannot auto-derive Eq<UserProfile>: field `metadata` has type `unknown` which lacks Eq
  --> src/user.ts:5:3
   |
 3 |   interface UserProfile {
 4 |     id: number;
 5 |     metadata: unknown;
   |     ^^^^^^^^ this field prevents auto-derivation
   |
   = note: `unknown` cannot implement Eq โ€” it could be anything
   = help: Use a concrete type instead of `unknown`, or provide @instance Eq<UserProfile>

Look up any error: npx typesugar --explain TS9101

Import Suggestions โ€‹

Missing an import? typesugar tells you where to find it:

error[TS9062]: Method `clamp` does not exist on type `number`
  --> src/math.ts:7:20
   |
 7 |   const safe = value.clamp(0, 100);
   |                      ^^^^^
   |
   = help: Did you mean to import?
     + import { clamp } from "@typesugar/std";

Opt-Out When You Need To โ€‹

typescript
"use no typesugar"; // whole file
function debug() {
  "use no typesugar";
} // one function
specialize(add); // @ts-no-typesugar     // one line
("use no typesugar extensions"); // just extensions

Error Messages Guide ยท Developer Experience Guide ยท Opt-Out Guide ยท Error Reference ยท Performance Architecture


Packages โ€‹

Build Infrastructure โ€‹

PackageDescription
typesugarUmbrella package
@typesugar/coreMacro registration and types
@typesugar/transformerTypeScript transformer (ts-patch)
unplugin-typesugarBundler plugins (Vite, esbuild, Rollup, Webpack)

Standard Library โ€‹

PackageDescription
@typesugar/stdExtension methods, pattern matching, do-notation, standard typeclasses

Typeclasses & Derivation โ€‹

PackageDescription
@typesugar/typeclass@typeclass, @instance, summon()
@typesugar/derive@derive(Eq, Clone, Debug, Json, ...)
@typesugar/specializeZero-cost typeclass specialization
@typesugar/reflecttypeInfo<T>(), fieldNames<T>(), validator<T>()

Syntax Sugar โ€‹

PackageDescription
@typesugar/stringsregex, html, raw tagged templates

Type Safety & Contracts โ€‹

PackageDescription
@typesugar/type-systemRefined types, newtype, HKT, phantom types
@typesugar/contractsrequires:, ensures:, @invariant
@typesugar/contracts-refinedRefinement type integration
@typesugar/validateSchema validation macros
@typesugar/unitsType-safe physical units

Data Structures & Algorithms โ€‹

PackageDescription
@typesugar/fpOption, Either, IO, Result, List
@typesugar/hlistHeterogeneous lists
@typesugar/fusionIterator fusion, expression templates
@typesugar/parserPEG parser generation
@typesugar/graphGraph algorithms, state machines
@typesugar/erasedType erasure / dyn Trait
@typesugar/codecVersioned codecs, schema evolution
@typesugar/mathMath types and typeclasses
@typesugar/mapperZero-cost object mapping

Ecosystem Integrations โ€‹

PackageDescription
@typesugar/effectEffect-TS adapter
@typesugar/sqlDoobie-like SQL

Developer Experience โ€‹

PackageDescription
@typesugar/vscodeVS Code/Cursor extension
@typesugar/eslint-pluginESLint processor and rules
@typesugar/testingPower assertions, property testing

Full Package Reference


Inspired by the Best โ€‹

typesugar draws from the best ideas across language ecosystems:

LanguageWhat it bringsPackages
Scala 3Typeclasses, extension methods, do-notationtypeclass, std, fp, effect, operators
RustDerive macros, zero-cost specialization, serde, dyn Traitderive, specialize, codec, erased, validate
ZigCompile-time evaluation and reflectioncomptime, reflect, preprocessor
C++ / BoostExpression templates, heterogeneous containers, parsersfusion, hlist, graph, parser, units
Haskell / MLRefinement types, type-level programming, property testingcontracts, contracts-refined, type-system, testing, math

Vision โ€‹

Long-term vision documents for typesugar's future:

Released under the MIT License.