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;
}