TypeScript Support - atdts¶
This documentation is incomplete. Your help would be appreciated! In particular, some how-to guides would be great.
Tutorials¶
Hello World¶
Install atdts
with opam
:
opam install atdts
Create a file hello.atd
containing this:
type message = {
subject: string;
body: string;
}
Call atdts
to produce hello.ts
:
$ atdts hello.atd
There’s now a file hello.ts
that contains a class looking like
this:
...
export type Message = {
subject: string;
body: string;
}
export function writeMessage(x: Message, context: any = x): any {
...
}
export function readMessage(x: any, context: any = x): Message {
...
}
...
Let’s write a TypeScript program say_hello.ts
that uses this code:
import * as hello from "./hello"
const msg: hello.Message = {
subject: "Hello",
body: "Dear friend, I hope you are well."
}
console.log(JSON.stringify(hello.writeMessage(msg)))
Running it will print the JSON message:
$ tsc --lib es2017,dom say_hello.ts
{"subject":"Hello","body":"Dear friend, I hope you are well."}
Such JSON data can be parsed. Let’s write a program
read_message.ts
that consumes JSON data from standard input:
import * as hello from "./hello"
import * as readline from "readline"
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
})
rl.question('', (data: string) => {
const msg = hello.readMessage(JSON.parse(data))
console.log("subject: " + msg.subject)
})
Output:
# Install dependencies
$ npm install --save-dev @types/node
$ npm install readline
# Compile
$ tsc --lib es2017,dom read_message.ts
# Run
$ echo '{"subject": "big news", "body": ""}' | js read_message.js
subject: big news
It works! But what happens if the JSON data lacks a "subject"
field? Let’s see:
$ echo '{"body": ""}' | js read_message.js
{"body": ""}
readline.js:1086
throw err;
^
Error: missing field 'subject' in JSON object of type 'Message'
...
And what if our program also thought that the correct field name was
subj
rather than subject? Here’s read_message_wrong.ts
which
tries to access a subj
field:
import * as hello from "./hello"
import * as readline from "readline"
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
})
rl.question('', (data: string) => {
const msg = hello.readMessage(JSON.parse(data))
console.log("subject: " + msg.subj)
})
Let’s compile our program:
$ tsc --lib es2017,dom read_message_wrong.ts
read_message_wrong.ts:11:33 - error TS2339: Property 'subj' does not exist on type 'Message'.
11 console.log("subject: " + msg.subj)
~~~~
Found 1 error in read_message_wrong.ts:11
The typechecker detected that our program makes incorrect assumptions about the message format without running it.
ATD Records, JSON objects, TypeScript objects¶
An ATD file contains types that describe the structure of JSON
data. JSON objects map to TypeScript types and objects. They’re called
records in the ATD language. Let’s define a simple record type
in the file hello_plus.atd
:
type message = {
subject: string;
~body: string;
}
Note the ~ in front of the body
field. It means that this field
has a default value. Whenever the JSON field is missing from a JSON
object, a default value is assumed. The implicit default value for a
string is ""
.
Let’s add a signature
field whose default value isn’t the empty
string:
type message = {
subject: string;
~body: string;
~signature <ts default="'anonymous'">: string;
}
Finally, we’ll add an optional url
field that doesn’t take a default value
at all:
type message = {
subject: string;
~body: string;
~signature <ts default="'anonymous'">: string;
?url: string option;
}
Let’s generate the TypeScript code for this.
$ atdts hello_plus.atd
Let’s update our reader program read_message_plus.ts
to this:
import * as hello_plus from "./hello_plus"
import * as readline from "readline"
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
})
rl.question('', (data: string) => {
const msg = hello_plus.readMessage(JSON.parse(data))
console.log(msg)
})
We can test it, showing us the final value of each field:
$ tsc --lib es2017,dom read_message_plus.ts
$ echo '{"subject":"hi"}' | js read_message_plus.js
{"subject":"hi"}
{ subject: 'hi',
body: '',
signature: 'anonymous',
url: undefined }
How-to guides¶
Defining default field values¶
[missing]
Renaming field names¶
[missing]
Deep dives¶
[missing]
Reference¶
Type mapping¶
ATD type |
TypeScript type |
JSON example |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
anything |
|
|
|
|
|
|
|
|
*the Int
type is an alias for number
but additionally, the
read and write functions generated by atdts check that the number
is a whole number.
Supported ATD annotations¶
Default field values¶
Record fields following a ~
assume a default value. The default value can
be implicit as mandated by the ATD language specification (false for
bool
, zero for int
, etc.) or it can be a user-provided value.
A user-provided default uses an annotation of the form
<ts default="VALUE">
where VALUE
evaluates to a TypeScript
expression e.g.
type foo = {
~answer <ts default="42">: int;
}
For example, the JSON value {}
will be read as {answer: 42}
.
Field and constructor renaming¶
Alternate JSON object field names can be specified using an annotation
of the form <json name="NAME">
where NAME
is the desired field
name to be used in the JSON representation. For example, the following
specifies the JSON name of the id
field is ID
:
type foo = {
id <json name="ID">: string
}
Similarly, the constructor names of sum types can also be given alternate names in the JSON representation. Here’s an example:
type bar = [
| Alpha <json name="alpha">
| Beta <json name="beta"> of int
]
Alternate representations for association lists¶
List of pairs can be represented by JSON objects or by TypeScript maps if the correct annotations are provided:
(string * bar) list <json repr="object">
will use JSON objects to represent a list of pairs of TypeScript type[string, Bar][]
. Using the annotation<json repr="array">
is equivalent to the default.(foo * bar) list <ts repr="map">
will use a TypeScript map of typeMap<Foo, Bar>
to represent the association list. Using the annotation<ts repr="array">
is equivalent to the default.
Caveats¶
Generated typescript contains a flag telling the compiler not to run checks on the file. (Read)