Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

TypeScript types

Requires the typescript Cargo feature.

With our TypeScriptRenderer, you can generate TypeScript types for all types that implement Schematic. To utilize, instantiate a generator, add types to render, and generate the output file.

#![allow(unused)]
fn main() {
use schematic::schema::{SchemaGenerator, TypeScriptRenderer};

let mut generator = SchemaGenerator::default();
generator.add::<CustomType>();
generator.generate(output_dir.join("types.ts"), TypeScriptRenderer::default())?;
}

For a reference implementation, check out moonrepo/moon.

Options

Custom options can be passed to the renderer using TypeScriptOptions.

#![allow(unused)]
fn main() {
use schematic::schema::TypeScriptOptions;

TypeScriptRenderer::new(TypeScriptOptions {
	// ...
	..TypeScriptOptions::default()
});
}

Indentation

The indentation of the generated TypeScript code can be customized using the indent_char option. By default this is a tab (\t).

#![allow(unused)]
fn main() {
TypeScriptOptions {
	// ...
	indent_char: "  ".into(),
}
}

Enum types

Enum types can be rendered in a format of your choice using the enum_format option and the EnumFormat enum. By default enums are rendered as TypeScript string unions, but can be rendered as TypeScript enums instead.

#![allow(unused)]
fn main() {
TypeScriptOptions {
	// ...
	enum_format: EnumFormat::Enum,
}
}
// Default
export type LogLevel = "debug" | "info" | "error";

// As enum
export enum LogLevel {
	Debug,
	Info,
	Error,
}

Furthermore, the const_enum option can be enabled to render const enum types instead of enum types. This does not apply when EnumFormat::Union is used.

#![allow(unused)]
fn main() {
TypeScriptOptions {
	// ...
	const_enum: true,
}
}
// Enabled
export const enum LogLevel {}

// Disabled
export enum LogLevel {}

Object types

Struct types can be rendered as either TypeScript interfaces or type aliases using the object_format option and the ObjectFormat enum. By default structs are rendered as TypeScript interfaces.

#![allow(unused)]
fn main() {
TypeScriptOptions {
	// ...
	object_format: ObjectFormat::Type,
}
}
// Default
export interface User {
	name: string;
}

// As alias
export type User = {
	name: string;
};

Properties format

Properties within a struct can be rendered as either optional or required in TypeScript, depending on usage. The default format for all properties can be customized with the property_format option and the PropertyFormat enum. By default all properties are required.

#![allow(unused)]
fn main() {
TypeScriptOptions {
	// ...
	property_format: PropertyFormat::Required,
}
}
// Default / required
export interface User {
	name: string;
}

// Optional
export interface User {
	name?: string;
}

// Optional with undefined union
export interface User {
	name?: string | undefined;
}

Type references

In the context of this renderer, a type reference is simply a reference to another type by its name, and is used by other types of another name. For example, the fields of a struct type may reference another type by name.

export type UserStatus = "active" | "inactive";

export interface User {
	status: UserStatus;
}

Depending on your use case, this may not be desirable. If so, you can enable the disable_references option, which disables references entirely, and inlines all type information. So the example above would become:

#![allow(unused)]
fn main() {
TypeScriptOptions {
	// ...
	disable_references: true,
}
}
export type UserStatus = "active" | "inactive";

export interface User {
	status: "active" | "inactive";
}

Additionally, the exclude_references option can be used to exclude a type reference by name entirely from the output, as demonstrated below.

#![allow(unused)]
fn main() {
TypeScriptOptions {
	// ...
	exclude_references: vec!["UserStatus".into()],
}
}
export interface User {
	status: "active" | "inactive";
}

Importing external types

For better interoperability, you can import external types from other TypeScript modules using the external_types option, which is a map of file paths (relative from the output location) to a list of types to import from that file. This is useful if:

  • You have existing types that aren’t generated and want to reference.
  • You want to reference types from other generated files, and don’t want to duplicate them.
#![allow(unused)]
fn main() {
TypeScriptOptions {
	// ...
	external_types: HashMap::from_iter([
		("./states".into(), vec!["UserStatus".into()]),
	]),
}
}
import type { UserStatus } from "./states";

export interface User {
	status: UserStatus;
}