1 | # Babel Typecheck
|
2 |
|
3 | This 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.0 tag](https://github.com/codemix/babel-plugin-typecheck/tree/2.0.0).
|
8 |
|
9 | # What?
|
10 |
|
11 | Turns code like this:
|
12 | ```js
|
13 | function sendMessage (to: User, message: string): boolean {
|
14 | return socket.send(to, message);
|
15 | }
|
16 | ```
|
17 | into code like this:
|
18 | ```js
|
19 | function 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 |
|
30 | And 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
|
33 | function 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 |
|
42 | function bar (input: string = 123): string { // <-- SyntaxError: default value is not string
|
43 | return input + "456";
|
44 | }
|
45 | ```
|
46 |
|
47 | # Examples
|
48 |
|
49 | The basic format is similar to [Flow Type Annotations](http://flowtype.org/docs/type-annotations.html).
|
50 |
|
51 | Here are a few examples of annotations this plugin supports:
|
52 |
|
53 | ```js
|
54 | function foo(
|
55 | aNum: number,
|
56 | anOptionalString: ?string, // will allow null/undefined
|
57 | anObject: Object,
|
58 | aDate: Date,
|
59 | anError: Error,
|
60 | aUnionType: Object|string,
|
61 | aClass: User,
|
62 | aShape: {foo: number, bar: ?string},
|
63 | anArray: Array,
|
64 | arrayOf: string[] | Array<string>,
|
65 | {x, y}: {x: string, y: number}, // destructuring works
|
66 | es6Defaults: number = 42
|
67 | ) : number {
|
68 | return aNum;
|
69 | }
|
70 | ```
|
71 |
|
72 | # Optimization
|
73 |
|
74 | In cases where typecheck can statically verify that the return value is of the correct type, no type checks will be inserted, for instance:
|
75 | ```js
|
76 | function bar (): string|Object {
|
77 | if (Math.random() > 0.5) {
|
78 | return "yes";
|
79 | }
|
80 | else {
|
81 | return {
|
82 | message: "no"
|
83 | };
|
84 | }
|
85 | }
|
86 | ```
|
87 | will produce no type checks at all, because we can trivially tell that the function can only return one of the two permitted types.
|
88 | This is also true for simple cases like:
|
89 | ```js
|
90 | function createUser (): User {
|
91 | return new User(); // <-- no typecheck required
|
92 | }
|
93 | ```
|
94 | This 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:
|
95 | ```js
|
96 | function createUser (): User {
|
97 | return User.create(); // <-- produces runtime typecheck
|
98 | }
|
99 | ```
|
100 |
|
101 |
|
102 | ## Changes in 3.0.0
|
103 |
|
104 | ### Supports type aliases:
|
105 | ```js
|
106 | type Foo = string|number;
|
107 |
|
108 | function demo (input: Foo): string {
|
109 | return input + ' world';
|
110 | }
|
111 |
|
112 | demo('hello'); // ok
|
113 | demo(123); // ok
|
114 | demo(["not", "a", "Foo"]); // fails
|
115 | ```
|
116 |
|
117 | ### Better static type inference
|
118 | ```js
|
119 | function demo (input: string): string[] {
|
120 | return makeArray(input); // no return type check required, knows that makeArray is compatible
|
121 | }
|
122 |
|
123 | function makeArray (input: string): string[] {
|
124 | return [input];
|
125 | }
|
126 | ```
|
127 |
|
128 | ### Type propagation
|
129 | ```js
|
130 | function demo (input: string): User {
|
131 | const user = new User({name: input});
|
132 | return user; // No check required, knows that user is the correct type
|
133 | }
|
134 | ```
|
135 |
|
136 | ### Assignment tracking
|
137 | ```js
|
138 | let name: string = "bob";
|
139 |
|
140 | name = "Bob"; // ok
|
141 | name = makeString(); // ok
|
142 | name = 123; // SyntaxError, expected string not number
|
143 |
|
144 | function makeString (): string {
|
145 | return "Sally";
|
146 | }
|
147 | ```
|
148 |
|
149 | ### Type casting
|
150 | ```js
|
151 | let name: string = "bob";
|
152 |
|
153 | name = "Bob";
|
154 | ((name: number) = 123);
|
155 | name = 456;
|
156 | name = "fish"; // SyntaxError, expected number;
|
157 | ```
|
158 |
|
159 | ### Array type parameters
|
160 | ```js
|
161 | function demo (input: string[]): number {
|
162 | return input.length;
|
163 | }
|
164 |
|
165 | demo(["a", "b", "c"]); // ok
|
166 | demo([1, 2, 3]); // TypeError
|
167 | ```
|
168 |
|
169 | ### Shape tracking
|
170 | ```js
|
171 | type User = {
|
172 | name: string;
|
173 | email: string;
|
174 | };
|
175 |
|
176 | function demo (input: User): string {
|
177 | return input.name;
|
178 | }
|
179 |
|
180 | demo({}); // TypeError
|
181 | demo({name: 123, email: "test@test.com"}); // TypeError
|
182 | demo({name: "test", email: "test@test.com"}); // ok
|
183 | ```
|
184 |
|
185 | # Installation
|
186 |
|
187 | First, install via [npm](https://npmjs.org/package/babel-plugin-typecheck).
|
188 | ```sh
|
189 | npm install --save-dev babel-plugin-typecheck
|
190 | ```
|
191 | Then, in your babel configuration (usually in your `.babelrc` file), add `"typecheck"` to your list of plugins:
|
192 | ```json
|
193 | {
|
194 | "plugins": ["typecheck"]
|
195 | }
|
196 | ```
|
197 |
|
198 |
|
199 | # License
|
200 |
|
201 | Published by [codemix](http://codemix.com/) under a permissive MIT License, see [LICENSE.md](./LICENSE.md).
|
202 |
|