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(targetType="type")
Animal: {
Name: string
Sound: string
} @cuetsy(targetType="interface")
LeggedAnimal: Animal & {
Legs: int
} @cuetsy(targetType="interface")
Pets: "Cat" | "Dog" | "Horse" @cuetsy(targetType="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/sdboyer/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(targetType) |
---|---|---|
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(targetType="type") |
export type MyUnion = 1 | 2 | 3 | 4 | 5 | 6; |
CUE | TypeScript | @cuetsy(targetType) |
---|---|---|
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(targetType="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(targetType="interface")
BInterface: AInterface & {
BField: int
} @cuetsy(targetType="interface") |
export interface AInterface {
AField: string;
}
export interface BInterface extends AInterface {
BField: number;
} |
CUE | TypeScript | @cuetsy(targetType) |
---|---|---|
Disjunction, Struct | Enum | enum |
Cuetsy supports two ways of expressing TypeScript enums in CUE:
Disjunctions may be used in a very similar way to Union Types. The keys of the enum are automatically inferred as the titled camel-case variant of their value:
CUE | TypeScript |
---|---|
MyEnum: "foo" | "bar" | "baz" @cuetsy(targetType="enum") |
export enum MyEnum {
Bar = "bar",
Baz = "baz",
Foo = "foo",
} |
If the implicit keys are insufficient, the struct
based style gives more
control:
CUE | TypeScript |
---|---|
MyEnum: {
Foo: "foo"
iCanChoose: "whateverILike"
} @cuetsy(targetType="enum") |
export enum MyEnum {
Foo = "foo",
iCanChoose = "whateverILike",
} |
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(targetType="type")
MyDisjEnum: "foo" | *"bar" @cuetsy(targetType="enum")
MyStructEnum: {
A: "Foo"
B: "Bar" @cuetsy(enumDefault)
} @cuetsy(targetType="enum")
MyInterface: {
num: int | *6
txt: string | *"CUE"
enm: MyDisjEnum
} @cuetsy(targetType="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",
}; |