Skip to main content
Version: 0.2.0

Type System

Super.js provides a powerful type system that extends JavaScript with static type checking while maintaining full ECMA compliance. This page covers the type system in detail.

Type Inference

Super.js uses intelligent type inference to automatically determine types based on context:

// Automatic type inference
const message = "Hello World"; // string
const count = 42; // number
const isActive = true; // boolean
const items = [1, 2, 3]; // number[]
const user = { name: "John", age: 30 }; // { name: string, age: number }

// Function return type inference
function add(a: number, b: number) {
return a + b; // return type inferred as number
}

// Array type inference
const mixed = [1, "hello", true]; // (number | string | boolean)[]
const numbers = [1, 2, 3] as const; // readonly [1, 2, 3]

Basic Types

Primitive Types

// All JavaScript primitive types are supported
let str: string = "hello";
let num: number = 42;
let bool: boolean = true;
let n: null = null;
let u: undefined = undefined;
let sym: symbol = Symbol("key");
let big: bigint = 123n;

Object Types

// Object type annotation
let obj: object = { x: 10, y: 20 };

// Array types
let numbers: number[] = [1, 2, 3];
let strings: Array<string> = ["a", "b", "c"];
let matrix: number[][] = [[1, 2], [3, 4]];

// Tuple types
let tuple: [string, number] = ["hello", 10];
let optionalTuple: [string, number?] = ["hello"]; // second element optional
let restTuple: [string, ...number[]] = ["hello", 1, 2, 3];

Interface System

Basic Interfaces

interface User {
id: number;
name: string;
email: string;
age?: number; // Optional property
readonly createdAt: Date; // Read-only property
}

// Interface implementation
class UserAccount implements User {
constructor(
public id: number,
public name: string,
public email: string,
public age?: number
) {
this.createdAt = new Date();
}

readonly createdAt: Date;
}

Interface Extensions

interface Animal {
name: string;
makeSound(): string;
}

interface Dog extends Animal {
breed: string;
bark(): string;
}

interface Cat extends Animal {
color: string;
purr(): string;
}

// Multiple interface extension
interface Pet extends Dog, Cat {
owner: string;
}

Index Signatures

interface StringArray {
[index: number]: string;
}

interface Dictionary {
[key: string]: any;
}

interface NumberDictionary {
[key: string]: number;
length: number; // Required property
name: string; // Error: string not assignable to number
}

Advanced Types

Union Types

type StringOrNumber = string | number;
type Status = "pending" | "success" | "error";
type Shape = Circle | Square | Triangle;

function processValue(value: StringOrNumber): string {
if (typeof value === "string") {
return value.toUpperCase();
} else {
return value.toString();
}
}

// Discriminated unions
interface Circle {
kind: "circle";
radius: number;
}

interface Square {
kind: "square";
sideLength: number;
}

type Shape = Circle | Square;

function getArea(shape: Shape): number {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2;
case "square":
return shape.sideLength ** 2;
}
}

Intersection Types

interface HasName {
name: string;
}

interface HasAge {
age: number;
}

interface HasEmail {
email: string;
}

type Person = HasName & HasAge;
type Contact = HasName & HasEmail;
type FullProfile = HasName & HasAge & HasEmail;

// Function intersection
type Callable = {
(): string;
(x: number): string;
};

type Describable = {
description: string;
};

type CallableAndDescribable = Callable & Describable;

Conditional Types

type NonNullable<T> = T extends null | undefined ? never : T;
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
type InstanceType<T> = T extends new (...args: any[]) => infer R ? R : any;

// Conditional type with multiple conditions
type TypeName<T> = T extends string
? "string"
: T extends number
? "number"
: T extends boolean
? "boolean"
: T extends undefined
? "undefined"
: T extends Function
? "function"
: "object";

Mapped Types

// Make all properties optional
type Partial<T> = {
[P in keyof T]?: T[P];
};

// Make all properties required
type Required<T> = {
[P in keyof T]-?: T[P];
};

// Make all properties read-only
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};

// Pick specific properties
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};

// Omit specific properties
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

Generic Types

Generic Functions

function identity<T>(arg: T): T {
return arg;
}

function firstElement<T>(arr: T[]): T | undefined {
return arr[0];
}

function merge<T, U>(obj1: T, obj2: U): T & U {
return { ...obj1, ...obj2 };
}

// Generic constraints
interface Lengthwise {
length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length);
return arg;
}

Generic Interfaces

interface Repository<T> {
find(id: number): T | null;
save(item: T): void;
delete(id: number): boolean;
findAll(): T[];
}

interface Cache<T> {
get(key: string): T | undefined;
set(key: string, value: T): void;
clear(): void;
}

Generic Classes

class Stack<T> {
private items: T[] = [];

push(item: T): void {
this.items.push(item);
}

pop(): T | undefined {
return this.items.pop();
}

peek(): T | undefined {
return this.items[this.items.length - 1];
}

isEmpty(): boolean {
return this.items.length === 0;
}

size(): number {
return this.items.length;
}
}

// Generic class with constraints
class NumberStack<T extends number> extends Stack<T> {
sum(): number {
return this.items.reduce((acc, item) => acc + item, 0);
}
}

Type Guards

Built-in Type Guards

function processValue(value: unknown): string {
if (typeof value === "string") {
return value.toUpperCase();
} else if (typeof value === "number") {
return value.toString();
} else if (typeof value === "boolean") {
return value ? "true" : "false";
} else if (value === null) {
return "null";
} else if (value === undefined) {
return "undefined";
} else if (Array.isArray(value)) {
return value.join(", ");
} else if (typeof value === "object") {
return JSON.stringify(value);
}
return "unknown";
}

Custom Type Guards

function isString(value: unknown): value is string {
return typeof value === "string";
}

function isNumber(value: unknown): value is number {
return typeof value === "number" && !isNaN(value);
}

function isArray<T>(value: unknown): value is T[] {
return Array.isArray(value);
}

function isUser(value: unknown): value is User {
return (
typeof value === "object" &&
value !== null &&
"id" in value &&
"name" in value &&
"email" in value
);
}

// Usage
function processUserData(data: unknown): User | null {
if (isUser(data)) {
return data; // Type is narrowed to User
}
return null;
}

Utility Types

Built-in Utility Types

interface User {
id: number;
name: string;
email: string;
age?: number;
readonly createdAt: Date;
}

// Partial - makes all properties optional
type PartialUser = Partial<User>;

// Required - makes all properties required
type RequiredUser = Required<User>;

// Readonly - makes all properties read-only
type ReadonlyUser = Readonly<User>;

// Pick - select specific properties
type UserBasic = Pick<User, "name" | "email">;

// Omit - exclude specific properties
type UserWithoutId = Omit<User, "id">;

// Record - create object type with specific keys
type UserMap = Record<string, User>;

// Exclude - exclude types from union
type NonNullableUser = Exclude<User | null | undefined, null | undefined>;

// Extract - extract types from union
type StringOrNumber = string | number;
type OnlyString = Extract<StringOrNumber, string>;

// ReturnType - get return type of function
type AddReturnType = ReturnType<typeof add>;

// Parameters - get parameter types of function
type AddParameters = Parameters<typeof add>;

// InstanceType - get instance type of class
type UserInstance = InstanceType<typeof UserAccount>;

Custom Utility Types

// Deep partial
type DeepPartial<T> = {
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};

// Deep readonly
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
};

// Function type utilities
type AsyncFunction<T> = () => Promise<T>;
type Callback<T> = (value: T) => void;
type EventHandler<T> = (event: T) => void;

// Object type utilities
type KeysOfType<T, U> = {
[K in keyof T]: T[K] extends U ? K : never;
}[keyof T];

type OptionalKeys<T> = KeysOfType<T, undefined>;
type RequiredKeys<T> = Exclude<keyof T, OptionalKeys<T>>;

Type Assertions

Type Assertion Syntax

// Angle-bracket syntax
let someValue: unknown = "this is a string";
let strLength: number = (<string>someValue).length;

// As syntax (preferred)
let strLength2: number = (someValue as string).length;

// Const assertions
const colors = ["red", "green", "blue"] as const;
type Color = typeof colors[number]; // "red" | "green" | "blue"

// Type assertion functions
function assertIsString(value: unknown): asserts value is string {
if (typeof value !== "string") {
throw new Error("Value is not a string");
}
}

function assertIsNumber(value: unknown): asserts value is number {
if (typeof value !== "number") {
throw new Error("Value is not a number");
}
}

Type Compatibility

Structural Typing

interface Point {
x: number;
y: number;
}

interface NamedPoint {
x: number;
y: number;
name: string;
}

let point: Point = { x: 1, y: 2 };
let namedPoint: NamedPoint = { x: 1, y: 2, name: "origin" };

// NamedPoint is compatible with Point (has all required properties)
point = namedPoint; // OK

// Point is not compatible with NamedPoint (missing name property)
// namedPoint = point; // Error

Function Type Compatibility

// Parameter compatibility (contravariant)
interface Callback {
(x: number): void;
}

let callback: Callback = (x: number | string) => console.log(x); // Error
let callback2: Callback = (x: number) => console.log(x); // OK

// Return type compatibility (covariant)
interface Factory {
(): number;
}

let factory: Factory = () => "hello"; // Error
let factory2: Factory = () => 42; // OK

This comprehensive type system provides the foundation for building robust, type-safe applications with Super.js while maintaining full JavaScript compatibility.