TypeScript types
Requires the
typescriptCargo 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;
}