typescript_type_def/
type_expr.rs

1//! This module defines structs used to create static descriptions of TypeScript
2//! type definitions.
3
4/// A description of the type information required to produce a TypeScript type
5/// definition.
6#[derive(Debug, Clone, Copy)]
7pub enum TypeInfo {
8    /// This info describes a "native" TypeScript type which does not require a
9    /// type definition.
10    Native(NativeTypeInfo),
11    /// This info describes a "defined" TypeScript type which does require a
12    /// type definition.
13    Defined(DefinedTypeInfo),
14}
15
16/// Type information describing a "native" TypeScript type.
17///
18/// Native types have a definition which only uses built-in or pre-defined
19/// TypeScript types. Therefore a definition for them is not emitted, and they
20/// are referenced by their definition.
21#[derive(Debug, Clone, Copy)]
22pub struct NativeTypeInfo {
23    /// A type expression describing this native type.
24    pub r#ref: TypeExpr,
25}
26
27/// Type information describing a "defined" TypeScript type.
28///
29/// Defined types need to have a type definition emitted in the TypeScript
30/// module. They are referenced using their name.
31#[derive(Debug, Clone, Copy)]
32pub struct DefinedTypeInfo {
33    /// The definition of this type.
34    ///
35    /// # Implementation Note
36    /// The body of the definition **must** be *invariant* of the Rust
37    /// type's generic parameters. In other words, if the Rust type is generic,
38    /// its definition must be the same for any value of its generic
39    /// parameters. Where the definition needs to reference generic parameters,
40    /// you must instead use a placeholder type whose
41    /// [`INFO`](crate::emit::TypeDef::INFO) is [`TypeInfo::Native`] and the
42    /// native type reference is a [`TypeExpr::Name`] referencing the generic
43    /// parameter.
44    pub def: TypeDefinition,
45    /// The specific values of the generic arguments of this type for this
46    /// instance of the generic type.
47    ///
48    /// This list should contain references to the type info of each type
49    /// parameter of this Rust type. Unlike `def`, these values **should**
50    /// depend on the generic parameters of this type.
51    pub generic_args: List<TypeExpr>,
52}
53
54/// The TypeScript definition of a type.
55#[derive(Debug, Clone, Copy)]
56pub struct TypeDefinition {
57    /// The documentation for this type definition.
58    pub docs: Option<Docs>,
59    /// The namespace path for this type.
60    pub path: List<Ident>,
61    /// The name of this type.
62    pub name: Ident,
63    /// The generic variables for this type defintion.
64    ///
65    /// If empty, the type does not have generics.
66    pub generic_vars: List<Ident>,
67    /// The definition of this type.
68    pub def: TypeExpr,
69}
70
71/// A TypeScript type expression.
72///
73/// This type is not intended to cover _all_ possible TypeScript type syntax,
74/// only that which is needed by the types defined in this crate and as produced
75/// by [`#[derive(TypeDef)]`](macro@crate::TypeDef).
76#[derive(Debug, Clone, Copy)]
77pub enum TypeExpr {
78    /// A reference to another type.
79    Ref(&'static TypeInfo),
80    /// A reference to a bare type name which should already be defined.
81    Name(TypeName),
82    /// A type-level string literal.
83    String(TypeString),
84    /// A tuple type.
85    Tuple(TypeTuple),
86    /// An object type.
87    Object(TypeObject),
88    /// An array type.
89    Array(TypeArray),
90    /// A union type.
91    Union(TypeUnion),
92    /// An intersection type.
93    Intersection(TypeIntersection),
94}
95
96/// A reference to a built-in TypeScript type, analogous to a Rust path with
97/// optional generics.
98#[derive(Debug, Clone, Copy)]
99pub struct TypeName {
100    /// The namespace path for this type.
101    pub path: List<Ident>,
102    /// The name of this type.
103    pub name: Ident,
104    /// The generic arguments for this type.
105    ///
106    /// If empty, the type does not have generics.
107    pub generic_args: List<TypeExpr>,
108}
109
110/// A TypeScript type-level string literal.
111#[derive(Debug, Clone, Copy)]
112pub struct TypeString {
113    /// The documentation for this type string.
114    pub docs: Option<Docs>,
115    /// The value of this literal.
116    pub value: &'static str,
117}
118
119/// A TypeScript tuple type.
120///
121/// In TypeScript, tuples are represented as constant-length arrays where each
122/// element can have a distinct type. Values of these types are encoded as
123/// arrays in JSON, which are expected to have a constant length.
124#[derive(Debug, Clone, Copy)]
125pub struct TypeTuple {
126    /// The documentation for this tuple.
127    pub docs: Option<Docs>,
128    /// The types of the elements of this tuple.
129    ///
130    /// If the elements are empty, the only valid value for this type is the
131    /// empty array `[]`.
132    pub elements: List<TypeExpr>,
133}
134
135/// A TypeScript object type.
136#[derive(Debug, Clone, Copy)]
137pub struct TypeObject {
138    /// The documentation for this object.
139    pub docs: Option<Docs>,
140    /// The index signature of this object.
141    pub index_signature: Option<IndexSignature>,
142    /// The fields of this object.
143    pub fields: List<ObjectField>,
144}
145
146/// An index signature of a TypeScript object type.
147#[derive(Debug, Clone, Copy)]
148pub struct IndexSignature {
149    /// The documentation for this index signature.
150    pub docs: Option<Docs>,
151    /// The name of the index key.
152    pub name: Ident,
153    /// The type of the index value.
154    pub value: &'static TypeExpr,
155}
156
157/// A field of a TypeScript object type.
158#[derive(Debug, Clone, Copy)]
159pub struct ObjectField {
160    /// The documentation for this field.
161    pub docs: Option<Docs>,
162    /// The name of this field.
163    pub name: TypeString,
164    /// Whether this field is optional or not.
165    ///
166    /// This corresponds with the `?` suffix on the field name which makes it
167    /// valid to omit the field entirely from the object, effectively giving it
168    /// a value of `undefined`. In JSON, omitted optional fields are omitted
169    /// from the object serialization.
170    pub optional: bool,
171    /// The type of this field.
172    pub r#type: TypeExpr,
173}
174
175/// A TypeScript array type.
176///
177/// In TypeScript, an array is distinct from a tuple by the fact that it may
178/// have any length and every element has the same type (although that type may
179/// be a union so the elements may have different runtime types). Values of both
180/// of these types are encoded as arrays in JSON.
181#[derive(Debug, Clone, Copy)]
182pub struct TypeArray {
183    /// The documentation for this array.
184    pub docs: Option<Docs>,
185    /// The type of items of this array.
186    pub item: &'static TypeExpr,
187}
188
189/// A TypeScript union type.
190#[derive(Debug, Clone, Copy)]
191pub struct TypeUnion {
192    /// The documentation for this union.
193    pub docs: Option<Docs>,
194    /// The types that comprise this union.
195    ///
196    /// If the members are empty, this type describes the vacuous union type
197    /// which is equivalent to `never`. If the members contain only one type,
198    /// this type is equivalent to that type.
199    pub members: List<TypeExpr>,
200}
201
202/// A TypeScript intersection type.
203///
204/// Note that not all valid TypeScript intersection types are possible to
205/// represent using JSON. In general, only object types with disjoint fields can
206/// be intersected and still be accurately encoded as JSON (the resulting type
207/// being an object with the combined fields of all the intersection members).
208#[derive(Debug, Clone, Copy)]
209pub struct TypeIntersection {
210    /// The documentation for this intersection.
211    pub docs: Option<Docs>,
212    /// The types that comprise this intersection.
213    ///
214    /// If the members are empty, this type describes the vacuous intersection
215    /// type which is equivalent to `any`. If the members contain only one
216    /// type, this type is equivalent to that type.
217    pub members: List<TypeExpr>,
218}
219
220/// A TypeScript identifier.
221///
222/// Note that TypeScript's rules for valid identifiers are not checked by this
223/// library. It is the user's responsibility to ensure that all identifiers are
224/// valid in TypeScript in order for the resulting TypeScript module to be
225/// valid.
226#[derive(Debug, Clone, Copy)]
227pub struct Ident(pub &'static str);
228
229/// A documentation string.
230///
231/// The string value should be the plain unformatted documentation without any
232/// `/**` or indentation in it. Lines may be separate by newlines.
233#[derive(Debug, Clone, Copy)]
234pub struct Docs(pub &'static str);
235
236/// An alias for lists used in type expressions.
237pub type List<T> = &'static [T];
238
239impl TypeExpr {
240    /// A helper function to create a type expression representing just an
241    /// identifier.
242    pub const fn ident(ident: Ident) -> Self {
243        Self::Name(TypeName::ident(ident))
244    }
245}
246
247impl TypeName {
248    /// A helper function to create a type name representing just an identifier.
249    pub const fn ident(ident: Ident) -> Self {
250        Self {
251            path: &[],
252            name: ident,
253            generic_args: &[],
254        }
255    }
256}