UNPKG

6.25 kBMarkdownView Raw
1# Babel Typecheck
2
3This is a [Babel](https://babeljs.io/) plugin for static and runtime type checking using [flow type](http://flowtype.org/) annotations.
4
5[![Build Status](https://travis-ci.org/codemix/babel-plugin-typecheck.svg)](https://travis-ci.org/codemix/babel-plugin-typecheck)
6
7> Note: Now requires babel 6.1, babel 5 users [see the 2.x branch](https://github.com/codemix/babel-plugin-typecheck/tree/2.x).
8
9# What?
10
11Turns code like this:
12```js
13function sendMessage (to: User, message: string): boolean {
14 return socket.send(to, message);
15}
16```
17into code like this:
18```js
19function sendMessage(to, message) {
20 var _socket$send;
21
22 if (!(to instanceof User)) throw new TypeError("Value of argument 'to' violates contract.");
23 if (typeof message !== "string") throw new TypeError("Value of argument 'message' violates contract.");
24 _socket$send = socket.send(to, message);
25 if (typeof _socket$send !== "boolean") throw new TypeError("Function 'sendMessage' return value violates contract.");
26 return _socket$send;
27}
28```
29
30And guards against some silly mistakes, for example the following code will fail to compile with a `SyntaxError`, because the function can return the wrong type.
31
32```js
33function foo (): boolean {
34 if (Math.random() > 0.5) {
35 return "yes"; // <-- SyntaxError - string is not boolean
36 }
37 else {
38 return false;
39 }
40}
41
42function bar (input: string = 123): string { // <-- SyntaxError: default value is not string
43 return input + "456";
44}
45```
46
47# Installation
48
49First, install via [npm](https://npmjs.org/package/babel-plugin-typecheck).
50```sh
51npm install --save-dev babel-plugin-typecheck
52```
53Then, in your babel configuration (usually in your `.babelrc` file), add `"typecheck"` to your list of plugins:
54```json
55{
56 "plugins": ["typecheck"]
57}
58```
59
60**Important**: This plugin has a dependency on `babel-plugin-syntax-flow` and `babel-plugin-transform-flow-strip-types`.
61Without `syntax-flow`, babel will be unable to parse the flow annotation syntax.
62Without `transform-flow-strip-types`, the type annotations will be included in the output which will make it unparsable by JS engines.
63
64If you are not already using the `babel-preset-react` plugin, you **must** install those plugins and include them in your babel configuration (usually `.babelrc`). Put them *after* `typecheck` in the list, e.g.
65```json
66{
67 "plugins": ["typecheck", "syntax-flow", "transform-flow-strip-types"]
68}
69```
70If you *are* using `babel-preset-react` you can ignore this warning.
71
72# Examples
73
74The basic format is similar to [Flow Type Annotations](http://flowtype.org/docs/type-annotations.html).
75
76Here are a few examples of annotations this plugin supports:
77
78```js
79function foo(
80 aNum: number,
81 anOptionalString: ?string, // will allow null/undefined
82 anObject: Object,
83 aDate: Date,
84 anError: Error,
85 aUnionType: Object|string,
86 aClass: User,
87 aShape: {foo: number, bar: ?string},
88 anArray: Array,
89 arrayOf: string[] | Array<string>,
90 {x, y}: {x: string, y: number}, // destructuring works
91 es6Defaults: number = 42
92) : number {
93 return aNum;
94}
95```
96
97# Optimization
98
99In cases where typecheck can statically verify that the return value is of the correct type, no type checks will be inserted, for instance:
100```js
101function bar (): string|Object {
102 if (Math.random() > 0.5) {
103 return "yes";
104 }
105 else {
106 return {
107 message: "no"
108 };
109 }
110}
111```
112will produce no type checks at all, because we can trivially tell that the function can only return one of the two permitted types.
113This is also true for simple cases like:
114```js
115function createUser (): User {
116 return new User(); // <-- no typecheck required
117}
118```
119This is currently quite limited though, as the plugin can only statically infer the types of literals and very simple expressions, it can't (yet) statically verify e.g. the result of a function call. In those cases a runtime type check is required:
120```js
121function createUser (): User {
122 return User.create(); // <-- produces runtime typecheck
123}
124```
125
126
127## Changes in 3.0.0
128
129### Supports type aliases:
130```js
131type Foo = string|number;
132
133function demo (input: Foo): string {
134 return input + ' world';
135}
136
137demo('hello'); // ok
138demo(123); // ok
139demo(["not", "a", "Foo"]); // fails
140```
141
142### Better static type inference
143```js
144function demo (input: string): string[] {
145 return makeArray(input); // no return type check required, knows that makeArray is compatible
146}
147
148function makeArray (input: string): string[] {
149 return [input];
150}
151```
152
153### Type propagation
154```js
155function demo (input: string): User {
156 const user = new User({name: input});
157 return user; // No check required, knows that user is the correct type
158}
159```
160
161### Assignment tracking
162```js
163let name: string = "bob";
164
165name = "Bob"; // ok
166name = makeString(); // ok
167name = 123; // SyntaxError, expected string not number
168
169function makeString (): string {
170 return "Sally";
171}
172```
173
174### Type casting
175```js
176let name: string = "bob";
177
178name = "Bob";
179((name: number) = 123);
180name = 456;
181name = "fish"; // SyntaxError, expected number;
182```
183
184### Array type parameters
185```js
186function demo (input: string[]): number {
187 return input.length;
188}
189
190demo(["a", "b", "c"]); // ok
191demo([1, 2, 3]); // TypeError
192```
193
194### Shape tracking
195```js
196type User = {
197 name: string;
198 email: string;
199};
200
201function demo (input: User): string {
202 return input.name;
203}
204
205demo({}); // TypeError
206demo({name: 123, email: "test@test.com"}); // TypeError
207demo({name: "test", email: "test@test.com"}); // ok
208```
209
210
211## Pragmas
212
213Sometimes you might need to disable type checking for a particular file or section of code.
214To ignore an entire file, add a comment at the top level scope of the file:
215```js
216// typecheck: ignore file
217export function wrong (input: string = 123): boolean {
218 return input + ' nope';
219}
220```
221
222To ignore a particular statement:
223```js
224let foo: string = "hello world";
225// typecheck: ignore statement
226foo = 123;
227```
228
229> Note: Because of how typecheck works, it's not possible to ignore individual lines, only entire statements or files.
230> So if you ignore e.g. an if statement, the entire body of that statement will be ignored.
231
232# License
233
234Published by [codemix](http://codemix.com/) under a permissive MIT License, see [LICENSE.md](./LICENSE.md).
235