Converting CUE objects to their TypeScript equivalent (highly experimental!)
- CUE makes defining and validating canonical data specification easy
- TypeScript is dominant in the frontend, but cannot natively benefit from this
- CUE types have direct TypeScript equivalents, so cuetsy can bridge this gap
CUE | TypeScript |
---|---|
DiceFaces: 1 | 2 | 3 | 4 | 5 | 6 @cuetsy(kind="type")
Animal: {
Name: string
Sound: string
} @cuetsy(kind="interface")
LeggedAnimal: Animal & {
Legs: int
} @cuetsy(kind="interface")
Pets: "Cat" | "Dog" | "Horse" @cuetsy(kind="enum") |
export type DiceFaces = 1 | 2 | 3 | 4 | 5 | 6;
export interface Animal {
Name: string;
Sound: string;
}
export interface LeggedAnimal extends Animal {
Legs: number;
}
export enum Pets {
Cat = "Cat",
Dog = "Dog",
Horse = "Horse",
} |
Cuetsy is in its early development, so it does not support all TypeScript features. However, the following are supported:
- Types
- Default
const
Cuetsy can be installed using Go 1.16+
$ go install github.com/grafana/cuetsy/cmd/cuetsy
cuetsy
must be invoked on files as follows:
$ cuetsy [file.cue]
This will create a logically equivalent [file].ts
CUE | TypeScript | @cuetsy(kind) |
---|---|---|
Disjunction | Union Type | type |
Union types are expressed in CUE and TypeScript nearly the same way, namely a
series of disjunctions (a | b | c
):
CUE | TypeScript |
---|---|
MyUnion: 1 | 2 | 3 | 4 | 5 | 6 @cuetsy(kind="type") |
export type MyUnion = 1 | 2 | 3 | 4 | 5 | 6; |
CUE | TypeScript | @cuetsy(kind) |
---|---|---|
Struct | Interface | interface |
TypeScript interfaces are expressed as regular structs in CUE.
Caveats:
- Nested structs are not supported
CUE | TypeScript |
---|---|
MyInterface: {
Num: number
Text: string
List: [...number]
Truth: bool
} @cuetsy(kind="interface") |
export interface MyInterface {
List: number[];
Num: number;
Text: string;
Truth: boolean;
} |
Interfaces can optionally inherit from another interface. This is expressed
using the union operator &
:
CUE | TypeScript |
---|---|
AInterface: {
AField: string
} @cuetsy(kind="interface")
BInterface: AInterface & {
BField: int
} @cuetsy(kind="interface") |
export interface AInterface {
AField: string;
}
export interface BInterface extends AInterface {
BField: number;
} |
CUE | TypeScript | @cuetsy(kind) |
---|---|---|
Disjunction, Struct | Enum | enum |
TypeScript's enums are union types, and are a mostly-exact mapping of what can be expressed with CUE's disjunctions. Disjunctions may contain only string or numeric values.
The member names (keys) of the TypeScript enum are automatically inferred as the
titled camel-case variant of their string value, but may be explicitly specified
using the memberNames
attribute. If the disjunction contains any numeric
values, memberNames
must be specified.
CUE | TypeScript |
---|---|
// Enum-level comment
// Foo: member-level comment
// Bar: member-level comment
AutoCamel: "foo" | "bar" @cuetsy(kind="enum")
// Enum-level comment
// Foo: member-level comment
// Bar: member-level comment
ManualCamel: "foo" | "bar" @cuetsy(kind="enum",memberNames="Foo|Bar")
Arbitrary: "foo" | "bar" @cuetsy(kind="enum",memberNames="Zip|Zap")
Numeric: 0 | 1 | 2 @cuetsy(kind="enum",memberNames="Zero|One|Two")
ErrMismatchLen: "a" | "b" | "c" @cuetsy(kind="enum",memberNames="a|b")
ErrNamelessNumerics: 0 | 1 | 2 @cuetsy(kind="enum") |
/**
* Enum-level comment
**/
enum AutoCamel {
// member-level comment
Foo = "foo",
// member-level comment
Bar = "bar",
}
/**
* Enum-level comment
**/
enum ManualCamel {
// member-level comment
Foo = "foo",
// member-level comment
Bar = "bar",
}
enum Arbitrary {
Zip = "foo",
Zap = "bar",
}
enum Numeric {
Zero = 0,
One = 1,
Two = 2,
} |
CUE | TypeScript |
---|---|
Defaults | const |
Cuetsy can optionally generate a const
for each type that holds default
values. For that, attach CUE Default
Values to your type
definitions:
CUE | TypeScript |
---|---|
MyUnion: 1 | 2 | *3 @cuetsy(kind="type")
MyDisjEnum: "foo" | *"bar" @cuetsy(kind="enum")
MyStructEnum: {
A: "Foo"
B: "Bar" @cuetsy(enumDefault)
} @cuetsy(kind="enum")
MyInterface: {
num: int | *6
txt: string | *"CUE"
enm: MyDisjEnum
} @cuetsy(kind="interface") |
export type MyUnion = 1 | 2 | 3;
export const myUnionDefault: MyUnion = 3;
export enum MyDisjEnum {
Bar = "bar",
Foo = "foo",
}
export const myDisjEnumDefault: MyDisjEnum = MyDisjEnum.Bar;
export enum MyStructEnum {
A = "Foo",
B = "Bar",
}
export const myStructEnumDefault: MyStructEnum = MyStructEnum.B;
export interface MyInterface {
enm: MyDisjEnum;
num: number;
txt: string;
}
export const myInterfaceDefault: MyInterface = {
enm: myDisjEnumDefault,
num: 6,
txt: "CUE",
}; |