Skip to content

Part 1 — Syntax rewrites

SuperJS rejects twelve TypeScript construct categories at parse or type-check time. There is no flag or pragma to re-enable them (ADR-004).

Quick reference

TypeScriptSuperJSError
anydynamicSJS-E004
A & B intersectiontype C extends A, B { }SJS-E005
T extends U ? A : Bsum type + matchSJS-E008
infer Tnot supported — explicit typesSJS-E009
enum E { ... }sum type / unit variantsSJS-E010
value! non-null assertionif / ?. narrowingSJS-E011
namespace N { }ES import / exportSJS-E012
{ [K in keyof T]: U } mappedstructural index signatureSJS-E006
T['key'] indexed accessname fields explicitlySJS-E006
typeof x in type positionexplicit type declarationSJS-E006
<T>expr angle castexpr as T onlyparse error
== / !==== / !==SJS-L003
@Decoratornot supportedbanned
prop?: T (optional)prop: T? or prop?: T per semantics

Decorators are not on the roadmap — they are incompatible with the ECMAScript-first emit model.


anydynamic

// TypeScript
function load(raw: any): string {
  return raw.toUpperCase()
}
// SuperJS
function load(raw: dynamic): string {
  if (typeof raw !== "string") {
    throw new Error("expected string")
  }
  return raw.toUpperCase()
}

dynamic is explicit and lintable. See dynamic type.


Intersection A & B → structural extends

// TypeScript
type Named = { name: string }
type Aged = { age: number }
type Person = Named & Aged
// SuperJS
type Named { name: string; }
type Aged { age: number; }
type Person extends Named, Aged { }

Conditional types → sum types + match

// TypeScript
type ApiResult<T> = T extends string ? { text: T } : { value: T }
// SuperJS
type TextResult(text: string) | ValueResult(value: dynamic)

function wrap(x: dynamic): TextResult | ValueResult {
  if (typeof x === "string") return TextResult(x)
  return ValueResult(x)
}

enum → sum types

// TypeScript
enum Status { Active, Inactive }
// SuperJS — unit variants
type Status = Active | Inactive

// With payload
type Status = Active(string) | Inactive

Non-null assertion ! → narrowing

// TypeScript
function len(s: string | null): number {
  return s!.length
}
// SuperJS
function len(s: string?): number {
  if (s === null) return 0
  return s.length
}

namespace → ES modules

// TypeScript
namespace Util {
  export function id<T>(x: T): T { return x }
}
// SuperJS — util.sjs
export function id<T>(x: T): T {
  return x
}

Mapped / indexed / typeof types → explicit shapes

// TypeScript
type Partial<T> = { [K in keyof T]?: T[K] }
type Name = Person["name"]
type Inferred = typeof someValue
// SuperJS — declare the shape you need
type StringMap {
  [key: string]: string;
}

type Person { name: string; age: number; }
// Use Person.name fields directly; no T["key"] operator

Optional and nullable properties

// TypeScript
interface Config {
  host: string
  port?: number
}
// SuperJS — nullable field (may be null when present)
type Config {
  host: string;
  port: number?;
}

See null safety: T? means T | null; optional prop?: T on object types means T | undefined when absent.


Next

Part 2 — Idiom changes

Documentation