rip-lang 2.8.9 → 2.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +39 -0
- package/README.md +39 -12
- package/docs/BROWSER.md +8 -8
- package/docs/GUIDE.md +13 -13
- package/docs/INTERNALS.md +11 -11
- package/docs/RATIONALE.md +180 -0
- package/docs/REACTIVITY.md +5 -5
- package/docs/TYPES.md +1132 -0
- package/docs/dist/rip.browser.js +12 -5
- package/docs/dist/rip.browser.min.js +10 -10
- package/docs/dist/rip.browser.min.js.br +0 -0
- package/docs/examples/README.md +21 -142
- package/docs/examples/arrows.rip +3 -13
- package/docs/examples/module.rip +41 -31
- package/docs/examples/reactivity.rip +48 -0
- package/package.json +1 -1
- package/src/compiler.js +13 -3
- package/src/grammar/grammar.rip +2 -2
- package/src/grammar/solar.rip +1 -1
- package/src/parser.js +1 -1
- package/docs/PHILOSOPHY.md +0 -569
- package/docs/WHY-NOT-COFFEESCRIPT.md +0 -186
- package/docs/WHY-YES-RIP.md +0 -757
- package/docs/examples/object-syntax.rip +0 -74
- package/docs/examples/prototype.rip +0 -30
- package/docs/examples/sexpr.rip +0 -128
- package/docs/examples/use-loader.js +0 -9
- package/docs/examples/utils.rip +0 -20
package/docs/TYPES.md
ADDED
|
@@ -0,0 +1,1132 @@
|
|
|
1
|
+
# Optional Types in Rip
|
|
2
|
+
|
|
3
|
+
> **Type-Driven Development Without the Overhead**
|
|
4
|
+
|
|
5
|
+
This specification defines Rip's optional, lightweight type system — a thin, compile-time-only layer that enables TypeScript-level type-driven development while preserving Rip's core philosophy: minimal syntax, high readability, zero runtime overhead.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Table of Contents
|
|
10
|
+
|
|
11
|
+
1. [Philosophy](#1-philosophy)
|
|
12
|
+
2. [Type Annotations](#2-type-annotations)
|
|
13
|
+
3. [Type Aliases](#3-type-aliases)
|
|
14
|
+
4. [Optionality Modifiers](#4-optionality-modifiers)
|
|
15
|
+
5. [Structural Types](#5-structural-types)
|
|
16
|
+
6. [Union Types](#6-union-types)
|
|
17
|
+
7. [Function Types](#7-function-types)
|
|
18
|
+
8. [Generic Types](#8-generic-types)
|
|
19
|
+
9. [Type Inference](#9-type-inference)
|
|
20
|
+
10. [Adoption Model](#10-adoption-model)
|
|
21
|
+
11. [Emission Strategy](#11-emission-strategy)
|
|
22
|
+
12. [Interfaces](#12-interfaces)
|
|
23
|
+
13. [Enums](#13-enums)
|
|
24
|
+
14. [Boundary Validation](#14-boundary-validation)
|
|
25
|
+
15. [Implementation Notes](#15-implementation-notes)
|
|
26
|
+
16. [Quick Reference](#16-quick-reference)
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
# 1. Philosophy
|
|
31
|
+
|
|
32
|
+
## Core Principles
|
|
33
|
+
|
|
34
|
+
1. **Types are additive, never required** — Rip code without types is valid Rip code
|
|
35
|
+
2. **All type syntax erases at runtime** — Zero performance cost
|
|
36
|
+
3. **Type syntax decorates existing constructs** — No new control flow or semantics
|
|
37
|
+
4. **No typechecker required in Rip** — Parse and preserve, don't enforce
|
|
38
|
+
5. **Emit TypeScript-compatible types** — Leverage existing tooling
|
|
39
|
+
6. **Prefer zero-runtime representations** — Unions over enums, types over classes
|
|
40
|
+
|
|
41
|
+
## The Rip Way
|
|
42
|
+
|
|
43
|
+
Types in Rip should feel like documentation that happens to be machine-readable:
|
|
44
|
+
|
|
45
|
+
```coffee
|
|
46
|
+
# Without types (valid)
|
|
47
|
+
def greet(name)
|
|
48
|
+
"Hello, #{name}!"
|
|
49
|
+
|
|
50
|
+
# With types (also valid, same runtime behavior)
|
|
51
|
+
def greet(name:: string):: string
|
|
52
|
+
"Hello, #{name}!"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Both compile to identical JavaScript. Types exist for developers and tools, not for the runtime.
|
|
56
|
+
|
|
57
|
+
## Static Typing as a Discipline, Not a Mandate
|
|
58
|
+
|
|
59
|
+
Rip's type system is designed for teams and projects that want:
|
|
60
|
+
|
|
61
|
+
- **IDE intelligence** — Autocompletion, hover info, refactoring support
|
|
62
|
+
- **Documentation** — Self-documenting function signatures
|
|
63
|
+
- **Boundary safety** — Confidence at API and module boundaries
|
|
64
|
+
- **Gradual adoption** — Add types where they matter, skip where they don't
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
# 2. Type Annotations
|
|
69
|
+
|
|
70
|
+
## Syntax: `::`
|
|
71
|
+
|
|
72
|
+
The double-colon `::` annotates types on variables, parameters, return values, and properties.
|
|
73
|
+
|
|
74
|
+
### Variables
|
|
75
|
+
|
|
76
|
+
```coffee
|
|
77
|
+
count:: number = 0
|
|
78
|
+
name:: string = "Rip"
|
|
79
|
+
active:: boolean = true
|
|
80
|
+
items:: string[] = []
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Emits to TypeScript:**
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
let count: number = 0;
|
|
87
|
+
let name: string = "Rip";
|
|
88
|
+
let active: boolean = true;
|
|
89
|
+
let items: string[] = [];
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Function Parameters
|
|
93
|
+
|
|
94
|
+
```coffee
|
|
95
|
+
def greet(name:: string)
|
|
96
|
+
"Hello, #{name}!"
|
|
97
|
+
|
|
98
|
+
def add(a:: number, b:: number)
|
|
99
|
+
a + b
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Emits:**
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
function greet(name: string) { ... }
|
|
106
|
+
function add(a: number, b: number) { ... }
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Return Types
|
|
110
|
+
|
|
111
|
+
```coffee
|
|
112
|
+
def getUser(id:: number):: User
|
|
113
|
+
db.find!(id)
|
|
114
|
+
|
|
115
|
+
def fetchData():: Promise<Data>
|
|
116
|
+
fetch!("/api/data")
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**Emits:**
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
function getUser(id: number): User { ... }
|
|
123
|
+
async function fetchData(): Promise<Data> { ... }
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Combined
|
|
127
|
+
|
|
128
|
+
```coffee
|
|
129
|
+
def processUser(id:: number, options:: Options):: Result
|
|
130
|
+
user = getUser!(id)
|
|
131
|
+
transform(user, options)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Constants
|
|
135
|
+
|
|
136
|
+
```coffee
|
|
137
|
+
MAX_RETRIES:: number =! 3
|
|
138
|
+
API_URL:: string =! "https://api.example.com"
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Emits:**
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
const MAX_RETRIES: number = 3;
|
|
145
|
+
const API_URL: string = "https://api.example.com";
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Reactive State
|
|
149
|
+
|
|
150
|
+
Types work with Rip's reactive operators:
|
|
151
|
+
|
|
152
|
+
```coffee
|
|
153
|
+
count:: number := 0 # Reactive state with type
|
|
154
|
+
doubled:: number ~= count * 2 # Computed with type
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
# 3. Type Aliases
|
|
160
|
+
|
|
161
|
+
## Syntax: `::=`
|
|
162
|
+
|
|
163
|
+
The `::=` operator declares a named type alias, mapping directly to TypeScript's `type X = ...`.
|
|
164
|
+
|
|
165
|
+
### Simple Aliases
|
|
166
|
+
|
|
167
|
+
```coffee
|
|
168
|
+
ID ::= number
|
|
169
|
+
Name ::= string
|
|
170
|
+
Timestamp ::= number
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**Emits:**
|
|
174
|
+
|
|
175
|
+
```ts
|
|
176
|
+
type ID = number;
|
|
177
|
+
type Name = string;
|
|
178
|
+
type Timestamp = number;
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Complex Types
|
|
182
|
+
|
|
183
|
+
```coffee
|
|
184
|
+
UserID ::= number | string
|
|
185
|
+
Callback ::= (error:: Error?, data:: any) -> void
|
|
186
|
+
Handler ::= (req:: Request, res:: Response) -> Promise<void>
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**Emits:**
|
|
190
|
+
|
|
191
|
+
```ts
|
|
192
|
+
type UserID = number | string;
|
|
193
|
+
type Callback = (error: Error | undefined, data: any) => void;
|
|
194
|
+
type Handler = (req: Request, res: Response) => Promise<void>;
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
# 4. Optionality Modifiers
|
|
200
|
+
|
|
201
|
+
Lightweight suffix operators that map directly to TypeScript unions.
|
|
202
|
+
|
|
203
|
+
## Optional: `T?`
|
|
204
|
+
|
|
205
|
+
Indicates a value may be undefined.
|
|
206
|
+
|
|
207
|
+
```coffee
|
|
208
|
+
email:: string?
|
|
209
|
+
callback:: Function?
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
**Emits:**
|
|
213
|
+
|
|
214
|
+
```ts
|
|
215
|
+
email: string | undefined
|
|
216
|
+
callback: Function | undefined
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Nullable Optional: `T??`
|
|
220
|
+
|
|
221
|
+
Indicates a value may be null or undefined.
|
|
222
|
+
|
|
223
|
+
```coffee
|
|
224
|
+
middle:: string??
|
|
225
|
+
cache:: Map<string, any>??
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**Emits:**
|
|
229
|
+
|
|
230
|
+
```ts
|
|
231
|
+
middle: string | null | undefined
|
|
232
|
+
cache: Map<string, any> | null | undefined
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Non-Nullable: `T!`
|
|
236
|
+
|
|
237
|
+
Asserts a value is never null or undefined.
|
|
238
|
+
|
|
239
|
+
```coffee
|
|
240
|
+
id:: ID!
|
|
241
|
+
user:: User!
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
**Emits:**
|
|
245
|
+
|
|
246
|
+
```ts
|
|
247
|
+
id: NonNullable<ID>
|
|
248
|
+
user: NonNullable<User>
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## In Function Signatures
|
|
252
|
+
|
|
253
|
+
```coffee
|
|
254
|
+
def findUser(id:: number):: User?
|
|
255
|
+
db.find(id) or undefined
|
|
256
|
+
|
|
257
|
+
def getUser(id:: number):: User!
|
|
258
|
+
db.find(id) ?? throw new Error "Not found"
|
|
259
|
+
|
|
260
|
+
def updateUser(id:: number, email:: string??):: boolean
|
|
261
|
+
...
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Optional Properties
|
|
265
|
+
|
|
266
|
+
In object types, `?` after the property name makes it optional:
|
|
267
|
+
|
|
268
|
+
```coffee
|
|
269
|
+
User ::= type
|
|
270
|
+
id: number
|
|
271
|
+
name: string
|
|
272
|
+
email?: string # Optional property
|
|
273
|
+
phone?: string? # Optional property that can also be undefined when present
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
# 5. Structural Types
|
|
279
|
+
|
|
280
|
+
## Object Types with `type` Block
|
|
281
|
+
|
|
282
|
+
Define structural types using the `type` keyword followed by a block:
|
|
283
|
+
|
|
284
|
+
```coffee
|
|
285
|
+
User ::= type
|
|
286
|
+
id: number
|
|
287
|
+
name: string
|
|
288
|
+
email?: string
|
|
289
|
+
createdAt: Date
|
|
290
|
+
|
|
291
|
+
Config ::= type
|
|
292
|
+
host: string
|
|
293
|
+
port: number
|
|
294
|
+
ssl?: boolean
|
|
295
|
+
timeout?: number
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
**Emits:**
|
|
299
|
+
|
|
300
|
+
```ts
|
|
301
|
+
type User = {
|
|
302
|
+
id: number;
|
|
303
|
+
name: string;
|
|
304
|
+
email?: string;
|
|
305
|
+
createdAt: Date;
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
type Config = {
|
|
309
|
+
host: string;
|
|
310
|
+
port: number;
|
|
311
|
+
ssl?: boolean;
|
|
312
|
+
timeout?: number;
|
|
313
|
+
};
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
## Nested Types
|
|
317
|
+
|
|
318
|
+
```coffee
|
|
319
|
+
Response ::= type
|
|
320
|
+
data: type
|
|
321
|
+
users: User[]
|
|
322
|
+
total: number
|
|
323
|
+
meta: type
|
|
324
|
+
page: number
|
|
325
|
+
limit: number
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
**Emits:**
|
|
329
|
+
|
|
330
|
+
```ts
|
|
331
|
+
type Response = {
|
|
332
|
+
data: {
|
|
333
|
+
users: User[];
|
|
334
|
+
total: number;
|
|
335
|
+
};
|
|
336
|
+
meta: {
|
|
337
|
+
page: number;
|
|
338
|
+
limit: number;
|
|
339
|
+
};
|
|
340
|
+
};
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
## Array Properties
|
|
344
|
+
|
|
345
|
+
```coffee
|
|
346
|
+
Collection ::= type
|
|
347
|
+
items: Item[]
|
|
348
|
+
tags: string[]
|
|
349
|
+
matrix: number[][]
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
## Readonly Properties
|
|
353
|
+
|
|
354
|
+
```coffee
|
|
355
|
+
ImmutableConfig ::= type
|
|
356
|
+
readonly host: string
|
|
357
|
+
readonly port: number
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
## Index Signatures
|
|
361
|
+
|
|
362
|
+
```coffee
|
|
363
|
+
Dictionary ::= type
|
|
364
|
+
[key: string]: any
|
|
365
|
+
|
|
366
|
+
StringMap ::= type
|
|
367
|
+
[key: string]: string
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
# 6. Union Types
|
|
373
|
+
|
|
374
|
+
## Inline Unions
|
|
375
|
+
|
|
376
|
+
```coffee
|
|
377
|
+
Status ::= "pending" | "active" | "done"
|
|
378
|
+
Result ::= Success | Error
|
|
379
|
+
ID ::= number | string
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
## Block Unions (Preferred)
|
|
383
|
+
|
|
384
|
+
For readability and diff-friendliness, use the block form with leading `|`:
|
|
385
|
+
|
|
386
|
+
```coffee
|
|
387
|
+
Status ::=
|
|
388
|
+
| "pending"
|
|
389
|
+
| "active"
|
|
390
|
+
| "done"
|
|
391
|
+
|
|
392
|
+
HttpMethod ::=
|
|
393
|
+
| "GET"
|
|
394
|
+
| "POST"
|
|
395
|
+
| "PUT"
|
|
396
|
+
| "PATCH"
|
|
397
|
+
| "DELETE"
|
|
398
|
+
|
|
399
|
+
Result ::=
|
|
400
|
+
| { success: true, data: Data }
|
|
401
|
+
| { success: false, error: Error }
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
**Emits:**
|
|
405
|
+
|
|
406
|
+
```ts
|
|
407
|
+
type Status = "pending" | "active" | "done";
|
|
408
|
+
|
|
409
|
+
type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
410
|
+
|
|
411
|
+
type Result =
|
|
412
|
+
| { success: true; data: Data }
|
|
413
|
+
| { success: false; error: Error };
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
## Why Block Unions Over Enums
|
|
417
|
+
|
|
418
|
+
Block unions have **zero runtime cost** — they exist only at compile time. Traditional enums generate runtime code:
|
|
419
|
+
|
|
420
|
+
```coffee
|
|
421
|
+
# Preferred: Zero runtime cost
|
|
422
|
+
Size ::=
|
|
423
|
+
| "xs"
|
|
424
|
+
| "sm"
|
|
425
|
+
| "md"
|
|
426
|
+
| "lg"
|
|
427
|
+
|
|
428
|
+
# Avoid: Generates runtime object
|
|
429
|
+
enum Size
|
|
430
|
+
xs
|
|
431
|
+
sm
|
|
432
|
+
md
|
|
433
|
+
lg
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
Use enums only when you need:
|
|
437
|
+
- Reverse mapping (value → name)
|
|
438
|
+
- Runtime iteration over values
|
|
439
|
+
- Explicit numeric values
|
|
440
|
+
|
|
441
|
+
---
|
|
442
|
+
|
|
443
|
+
# 7. Function Types
|
|
444
|
+
|
|
445
|
+
## Arrow Function Types
|
|
446
|
+
|
|
447
|
+
```coffee
|
|
448
|
+
Comparator ::= (a:: any, b:: any) -> number
|
|
449
|
+
AsyncFetcher ::= (url:: string) -> Promise<Response>
|
|
450
|
+
Callback ::= (err:: Error?, data:: any?) -> void
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
**Emits:**
|
|
454
|
+
|
|
455
|
+
```ts
|
|
456
|
+
type Comparator = (a: any, b: any) => number;
|
|
457
|
+
type AsyncFetcher = (url: string) => Promise<Response>;
|
|
458
|
+
type Callback = (err: Error | undefined, data: any | undefined) => void;
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
## Function Overloads
|
|
462
|
+
|
|
463
|
+
Multiple signatures for a single implementation:
|
|
464
|
+
|
|
465
|
+
```coffee
|
|
466
|
+
# Overload signatures
|
|
467
|
+
def toHtml(content:: string):: string
|
|
468
|
+
def toHtml(nodes:: Element[]):: string
|
|
469
|
+
def toHtml(fragment:: DocumentFragment):: string
|
|
470
|
+
|
|
471
|
+
# Implementation (matches last signature or uses widest type)
|
|
472
|
+
def toHtml(input:: any):: string
|
|
473
|
+
switch typeof input
|
|
474
|
+
when "string" then escapeHtml(input)
|
|
475
|
+
else renderNodes(input)
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
**Emits:**
|
|
479
|
+
|
|
480
|
+
```ts
|
|
481
|
+
function toHtml(content: string): string;
|
|
482
|
+
function toHtml(nodes: Element[]): string;
|
|
483
|
+
function toHtml(fragment: DocumentFragment): string;
|
|
484
|
+
function toHtml(input: any): string {
|
|
485
|
+
// implementation
|
|
486
|
+
}
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
## Method Signatures in Classes
|
|
490
|
+
|
|
491
|
+
```coffee
|
|
492
|
+
class UserService
|
|
493
|
+
find: (id:: number):: User? ->
|
|
494
|
+
@db.find(id)
|
|
495
|
+
|
|
496
|
+
create: (data:: CreateUserInput):: User ->
|
|
497
|
+
@db.create(data)
|
|
498
|
+
|
|
499
|
+
update: (id:: number, data:: UpdateUserInput):: User? ->
|
|
500
|
+
@db.update(id, data)
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
---
|
|
504
|
+
|
|
505
|
+
# 8. Generic Types
|
|
506
|
+
|
|
507
|
+
## Generic Type Parameters
|
|
508
|
+
|
|
509
|
+
```coffee
|
|
510
|
+
# Simple generic
|
|
511
|
+
Container<T> ::= type
|
|
512
|
+
value: T
|
|
513
|
+
|
|
514
|
+
# Multiple type parameters
|
|
515
|
+
Pair<K, V> ::= type
|
|
516
|
+
key: K
|
|
517
|
+
value: V
|
|
518
|
+
|
|
519
|
+
# With constraints
|
|
520
|
+
Comparable<T extends Ordered> ::= type
|
|
521
|
+
value: T
|
|
522
|
+
compareTo: (other:: T) -> number
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
**Emits:**
|
|
526
|
+
|
|
527
|
+
```ts
|
|
528
|
+
type Container<T> = {
|
|
529
|
+
value: T;
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
type Pair<K, V> = {
|
|
533
|
+
key: K;
|
|
534
|
+
value: V;
|
|
535
|
+
};
|
|
536
|
+
|
|
537
|
+
type Comparable<T extends Ordered> = {
|
|
538
|
+
value: T;
|
|
539
|
+
compareTo: (other: T) => number;
|
|
540
|
+
};
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
## Generic Functions
|
|
544
|
+
|
|
545
|
+
```coffee
|
|
546
|
+
def identity<T>(value:: T):: T
|
|
547
|
+
value
|
|
548
|
+
|
|
549
|
+
def map<T, U>(items:: T[], fn:: (item:: T) -> U):: U[]
|
|
550
|
+
items.map(fn)
|
|
551
|
+
|
|
552
|
+
def first<T>(items:: T[]):: T?
|
|
553
|
+
items[0]
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
## Generic Constraints
|
|
557
|
+
|
|
558
|
+
```coffee
|
|
559
|
+
def merge<T extends object, U extends object>(a:: T, b:: U):: T & U
|
|
560
|
+
{...a, ...b}
|
|
561
|
+
|
|
562
|
+
def stringify<T extends { toString: () -> string }>(value:: T):: string
|
|
563
|
+
value.toString()
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
---
|
|
567
|
+
|
|
568
|
+
# 9. Type Inference
|
|
569
|
+
|
|
570
|
+
## When to Annotate
|
|
571
|
+
|
|
572
|
+
Rip's type system uses **TypeScript-compatible inference**. Types should be explicit at boundaries, optional elsewhere:
|
|
573
|
+
|
|
574
|
+
### Explicit (Recommended)
|
|
575
|
+
|
|
576
|
+
```coffee
|
|
577
|
+
# Function signatures — always annotate
|
|
578
|
+
def processUser(id:: number, options:: ProcessOptions):: Result
|
|
579
|
+
...
|
|
580
|
+
|
|
581
|
+
# Exported values — always annotate
|
|
582
|
+
export config:: Config = loadConfig()
|
|
583
|
+
|
|
584
|
+
# Class properties — annotate for clarity
|
|
585
|
+
class UserService
|
|
586
|
+
db:: Database
|
|
587
|
+
cache:: Map<string, User>
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
### Inferred (Acceptable)
|
|
591
|
+
|
|
592
|
+
```coffee
|
|
593
|
+
# Local variables — let TypeScript infer
|
|
594
|
+
user = getUser!(id) # Inferred from getUser's return type
|
|
595
|
+
items = users.map (u) -> u.name # Inferred as string[]
|
|
596
|
+
count = 0 # Inferred as number
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
## Inference Rules
|
|
600
|
+
|
|
601
|
+
1. **Function returns** — Inferred from body if not annotated
|
|
602
|
+
2. **Variables** — Inferred from initializer
|
|
603
|
+
3. **Parameters** — Should be explicitly annotated
|
|
604
|
+
4. **Generic type args** — Often inferred from usage
|
|
605
|
+
|
|
606
|
+
---
|
|
607
|
+
|
|
608
|
+
# 10. Adoption Model
|
|
609
|
+
|
|
610
|
+
Types are optional at three levels: project, file, and line.
|
|
611
|
+
|
|
612
|
+
## Project Level
|
|
613
|
+
|
|
614
|
+
Configure in `package.json` or `rip.config.json`:
|
|
615
|
+
|
|
616
|
+
```json
|
|
617
|
+
{
|
|
618
|
+
"rip": {
|
|
619
|
+
"types": "emit"
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
| Mode | Behavior |
|
|
625
|
+
|------|----------|
|
|
626
|
+
| `"off"` | Ignore all type syntax (strip during parse) |
|
|
627
|
+
| `"emit"` | Parse types, emit `.d.ts` files |
|
|
628
|
+
| `"check"` | Parse types, emit `.d.ts`, run `tsc --noEmit` |
|
|
629
|
+
|
|
630
|
+
## File Level
|
|
631
|
+
|
|
632
|
+
Override project settings per-file with a directive comment:
|
|
633
|
+
|
|
634
|
+
```coffee
|
|
635
|
+
# @types off
|
|
636
|
+
# This file has no type checking
|
|
637
|
+
|
|
638
|
+
# @types emit
|
|
639
|
+
# Types parsed and emitted for this file
|
|
640
|
+
|
|
641
|
+
# @types check
|
|
642
|
+
# Types checked via TypeScript for this file
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
## Line Level
|
|
646
|
+
|
|
647
|
+
All type syntax is simply ignored if types are disabled. No special syntax needed — annotations silently disappear:
|
|
648
|
+
|
|
649
|
+
```coffee
|
|
650
|
+
# With types enabled:
|
|
651
|
+
count:: number = 0 # Type preserved
|
|
652
|
+
|
|
653
|
+
# With types disabled:
|
|
654
|
+
count:: number = 0 # Parses as: count = 0
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
## Gradual Adoption Path
|
|
658
|
+
|
|
659
|
+
1. **Start with `"off"`** — Write normal Rip code
|
|
660
|
+
2. **Enable `"emit"`** — Add types where helpful, get `.d.ts` for tooling
|
|
661
|
+
3. **Move to `"check"`** — Enforce type safety via TypeScript
|
|
662
|
+
|
|
663
|
+
---
|
|
664
|
+
|
|
665
|
+
# 11. Emission Strategy
|
|
666
|
+
|
|
667
|
+
## Compilation Outputs
|
|
668
|
+
|
|
669
|
+
| Input | Output | Purpose |
|
|
670
|
+
|-------|--------|---------|
|
|
671
|
+
| `file.rip` | `file.js` | Runtime code (always) |
|
|
672
|
+
| `file.rip` | `file.d.ts` | Type declarations (when `emit` or `check`) |
|
|
673
|
+
|
|
674
|
+
## Type Declaration Files
|
|
675
|
+
|
|
676
|
+
When `types: "emit"` or `types: "check"`, generate `.d.ts` files:
|
|
677
|
+
|
|
678
|
+
```coffee
|
|
679
|
+
# user.rip
|
|
680
|
+
export User ::= type
|
|
681
|
+
id: number
|
|
682
|
+
name: string
|
|
683
|
+
|
|
684
|
+
export def getUser(id:: number):: User?
|
|
685
|
+
db.find(id)
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
**Generates `user.d.ts`:**
|
|
689
|
+
|
|
690
|
+
```ts
|
|
691
|
+
export type User = {
|
|
692
|
+
id: number;
|
|
693
|
+
name: string;
|
|
694
|
+
};
|
|
695
|
+
|
|
696
|
+
export function getUser(id: number): User | undefined;
|
|
697
|
+
```
|
|
698
|
+
|
|
699
|
+
**Generates `user.js`:**
|
|
700
|
+
|
|
701
|
+
```js
|
|
702
|
+
export function getUser(id) {
|
|
703
|
+
return db.find(id);
|
|
704
|
+
}
|
|
705
|
+
```
|
|
706
|
+
|
|
707
|
+
## Type-Only Exports
|
|
708
|
+
|
|
709
|
+
Type aliases that have no runtime representation are only emitted to `.d.ts`:
|
|
710
|
+
|
|
711
|
+
```coffee
|
|
712
|
+
# These only appear in .d.ts, not .js
|
|
713
|
+
Status ::= "pending" | "active" | "done"
|
|
714
|
+
UserID ::= number
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
## Integration with TypeScript
|
|
718
|
+
|
|
719
|
+
When `types: "check"`:
|
|
720
|
+
|
|
721
|
+
1. Compile `.rip` → `.js` + `.d.ts`
|
|
722
|
+
2. Run `tsc --noEmit` to validate types
|
|
723
|
+
3. Report TypeScript errors
|
|
724
|
+
|
|
725
|
+
This leverages TypeScript's mature type checker without reimplementing it.
|
|
726
|
+
|
|
727
|
+
---
|
|
728
|
+
|
|
729
|
+
# 12. Interfaces
|
|
730
|
+
|
|
731
|
+
## Syntax: `interface`
|
|
732
|
+
|
|
733
|
+
For TypeScript compatibility, Rip also supports the `interface` keyword for object types:
|
|
734
|
+
|
|
735
|
+
```coffee
|
|
736
|
+
interface User
|
|
737
|
+
id: number
|
|
738
|
+
name: string
|
|
739
|
+
email?: string
|
|
740
|
+
```
|
|
741
|
+
|
|
742
|
+
**Emits:**
|
|
743
|
+
|
|
744
|
+
```ts
|
|
745
|
+
interface User {
|
|
746
|
+
id: number;
|
|
747
|
+
name: string;
|
|
748
|
+
email?: string;
|
|
749
|
+
}
|
|
750
|
+
```
|
|
751
|
+
|
|
752
|
+
## Type vs Interface
|
|
753
|
+
|
|
754
|
+
| Feature | `::= type` | `interface` |
|
|
755
|
+
|---------|------------|-------------|
|
|
756
|
+
| Declaration merging | No | Yes |
|
|
757
|
+
| Extends | Via `&` intersection | Via `extends` |
|
|
758
|
+
| Computed properties | Yes | No |
|
|
759
|
+
| Mapped types | Yes | No |
|
|
760
|
+
|
|
761
|
+
**Recommendation:** Use `::= type` by default. Use `interface` when you need declaration merging or prefer the interface aesthetic.
|
|
762
|
+
|
|
763
|
+
## Interface Extension
|
|
764
|
+
|
|
765
|
+
```coffee
|
|
766
|
+
interface Animal
|
|
767
|
+
name: string
|
|
768
|
+
|
|
769
|
+
interface Dog extends Animal
|
|
770
|
+
breed: string
|
|
771
|
+
bark: () -> void
|
|
772
|
+
```
|
|
773
|
+
|
|
774
|
+
---
|
|
775
|
+
|
|
776
|
+
# 13. Enums
|
|
777
|
+
|
|
778
|
+
## Zero-Runtime Enums (Preferred)
|
|
779
|
+
|
|
780
|
+
Use string literal unions for zero runtime cost:
|
|
781
|
+
|
|
782
|
+
```coffee
|
|
783
|
+
Size ::=
|
|
784
|
+
| "xs"
|
|
785
|
+
| "sm"
|
|
786
|
+
| "md"
|
|
787
|
+
| "lg"
|
|
788
|
+
| "xl"
|
|
789
|
+
|
|
790
|
+
Direction ::=
|
|
791
|
+
| "north"
|
|
792
|
+
| "south"
|
|
793
|
+
| "east"
|
|
794
|
+
| "west"
|
|
795
|
+
```
|
|
796
|
+
|
|
797
|
+
**Emits only to `.d.ts`:**
|
|
798
|
+
|
|
799
|
+
```ts
|
|
800
|
+
type Size = "xs" | "sm" | "md" | "lg" | "xl";
|
|
801
|
+
type Direction = "north" | "south" | "east" | "west";
|
|
802
|
+
```
|
|
803
|
+
|
|
804
|
+
## Runtime Enums (When Needed)
|
|
805
|
+
|
|
806
|
+
When you need runtime access to enum values, use the `enum` keyword:
|
|
807
|
+
|
|
808
|
+
```coffee
|
|
809
|
+
enum Status
|
|
810
|
+
pending
|
|
811
|
+
active
|
|
812
|
+
completed
|
|
813
|
+
cancelled
|
|
814
|
+
|
|
815
|
+
enum HttpCode
|
|
816
|
+
ok = 200
|
|
817
|
+
created = 201
|
|
818
|
+
badRequest = 400
|
|
819
|
+
notFound = 404
|
|
820
|
+
serverError = 500
|
|
821
|
+
```
|
|
822
|
+
|
|
823
|
+
**Emits to both `.js` and `.d.ts`:**
|
|
824
|
+
|
|
825
|
+
```ts
|
|
826
|
+
// .d.ts
|
|
827
|
+
enum Status {
|
|
828
|
+
pending,
|
|
829
|
+
active,
|
|
830
|
+
completed,
|
|
831
|
+
cancelled
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
// .js (runtime object generated)
|
|
835
|
+
const Status = {
|
|
836
|
+
pending: 0,
|
|
837
|
+
active: 1,
|
|
838
|
+
completed: 2,
|
|
839
|
+
cancelled: 3,
|
|
840
|
+
0: "pending",
|
|
841
|
+
1: "active",
|
|
842
|
+
2: "completed",
|
|
843
|
+
3: "cancelled"
|
|
844
|
+
};
|
|
845
|
+
```
|
|
846
|
+
|
|
847
|
+
## When to Use Runtime Enums
|
|
848
|
+
|
|
849
|
+
Use runtime enums only when you need:
|
|
850
|
+
|
|
851
|
+
- **Reverse mapping** — Get name from value: `Status[0]` → `"pending"`
|
|
852
|
+
- **Iteration** — Loop over all values at runtime
|
|
853
|
+
- **Explicit numeric values** — `HttpCode.ok === 200`
|
|
854
|
+
|
|
855
|
+
For all other cases, prefer zero-runtime union types.
|
|
856
|
+
|
|
857
|
+
---
|
|
858
|
+
|
|
859
|
+
# 14. Boundary Validation
|
|
860
|
+
|
|
861
|
+
## Philosophy
|
|
862
|
+
|
|
863
|
+
Types are compile-time contracts. For data entering your system (user input, API responses, file contents), **validate at boundaries**:
|
|
864
|
+
|
|
865
|
+
```coffee
|
|
866
|
+
# Type declares the shape
|
|
867
|
+
User ::= type
|
|
868
|
+
id: number
|
|
869
|
+
name: string
|
|
870
|
+
email: string
|
|
871
|
+
|
|
872
|
+
# Validation enforces at runtime
|
|
873
|
+
def parseUser(input:: unknown):: User
|
|
874
|
+
UserSchema.parse(input) # Throws if invalid
|
|
875
|
+
```
|
|
876
|
+
|
|
877
|
+
## Recommended Pattern
|
|
878
|
+
|
|
879
|
+
Use a validation library (like Zod) at IO boundaries:
|
|
880
|
+
|
|
881
|
+
```coffee
|
|
882
|
+
import { z } from "zod"
|
|
883
|
+
|
|
884
|
+
# Define schema with runtime validation
|
|
885
|
+
UserSchema = z.object
|
|
886
|
+
id: z.number()
|
|
887
|
+
name: z.string()
|
|
888
|
+
email: z.string().email()
|
|
889
|
+
|
|
890
|
+
# Derive type from schema (single source of truth)
|
|
891
|
+
User ::= z.infer<typeof UserSchema>
|
|
892
|
+
|
|
893
|
+
# Validate at API boundary
|
|
894
|
+
def createUser(req:: Request):: User
|
|
895
|
+
data = req.json!
|
|
896
|
+
UserSchema.parse(data) # Validates and returns typed data
|
|
897
|
+
```
|
|
898
|
+
|
|
899
|
+
## Trust Internally
|
|
900
|
+
|
|
901
|
+
Once data passes boundary validation, trust the types internally:
|
|
902
|
+
|
|
903
|
+
```coffee
|
|
904
|
+
def processUser(user:: User):: void
|
|
905
|
+
# No need to re-validate — type guarantees shape
|
|
906
|
+
sendWelcomeEmail(user.email)
|
|
907
|
+
createProfile(user.id, user.name)
|
|
908
|
+
```
|
|
909
|
+
|
|
910
|
+
---
|
|
911
|
+
|
|
912
|
+
# 15. Implementation Notes
|
|
913
|
+
|
|
914
|
+
## Parser Changes
|
|
915
|
+
|
|
916
|
+
The parser must recognize and preserve:
|
|
917
|
+
|
|
918
|
+
1. **`::` annotations** — After identifiers, parameters, before return
|
|
919
|
+
2. **`::=` declarations** — Type alias definitions
|
|
920
|
+
3. **Type modifiers** — `?`, `??`, `!` suffixes
|
|
921
|
+
4. **`type` blocks** — Structural type definitions
|
|
922
|
+
5. **Generic syntax** — `<T>`, `<T extends U>`, etc.
|
|
923
|
+
6. **Block unions** — Leading `|` for union members
|
|
924
|
+
|
|
925
|
+
## AST Representation
|
|
926
|
+
|
|
927
|
+
Type information should be stored as AST metadata:
|
|
928
|
+
|
|
929
|
+
```coffee
|
|
930
|
+
# Source
|
|
931
|
+
count:: number = 0
|
|
932
|
+
```
|
|
933
|
+
|
|
934
|
+
```javascript
|
|
935
|
+
// AST (conceptual)
|
|
936
|
+
["=", "count", 0, { type: "number" }]
|
|
937
|
+
```
|
|
938
|
+
|
|
939
|
+
## Code Generation
|
|
940
|
+
|
|
941
|
+
Type annotations should:
|
|
942
|
+
|
|
943
|
+
1. **Strip from runtime** — Never appear in `.js` output
|
|
944
|
+
2. **Preserve for `.d.ts`** — Emit valid TypeScript declarations
|
|
945
|
+
3. **Maintain source order** — Types in `.d.ts` match source file order
|
|
946
|
+
|
|
947
|
+
## Scope and Validation
|
|
948
|
+
|
|
949
|
+
Rip does **not** need to:
|
|
950
|
+
|
|
951
|
+
- Evaluate type expressions
|
|
952
|
+
- Prove type soundness
|
|
953
|
+
- Check type compatibility
|
|
954
|
+
- Resolve type references
|
|
955
|
+
|
|
956
|
+
Rip only needs to:
|
|
957
|
+
|
|
958
|
+
- **Parse** type syntax correctly
|
|
959
|
+
- **Preserve** type information in AST
|
|
960
|
+
- **Emit** valid TypeScript type syntax
|
|
961
|
+
|
|
962
|
+
All actual type checking is delegated to TypeScript when `types: "check"`.
|
|
963
|
+
|
|
964
|
+
---
|
|
965
|
+
|
|
966
|
+
## Summary
|
|
967
|
+
|
|
968
|
+
Rip's optional type system provides:
|
|
969
|
+
|
|
970
|
+
| Feature | Description |
|
|
971
|
+
|---------|-------------|
|
|
972
|
+
| **Type Annotations** | `::` for variables, parameters, returns |
|
|
973
|
+
| **Type Aliases** | `::=` for named types |
|
|
974
|
+
| **Optionality** | `T?` optional, `T??` nullable, `T!` non-null |
|
|
975
|
+
| **Structural Types** | `type` blocks for object shapes |
|
|
976
|
+
| **Union Types** | Inline or block form with `\|` |
|
|
977
|
+
| **Function Types** | Arrow syntax, overloads supported |
|
|
978
|
+
| **Generics** | Full generic support with constraints |
|
|
979
|
+
| **Adoption Levels** | Project, file, and line granularity |
|
|
980
|
+
| **Emission** | `.js` runtime + `.d.ts` declarations |
|
|
981
|
+
|
|
982
|
+
**The result:**
|
|
983
|
+
|
|
984
|
+
- Type-driven development with TypeScript ecosystem compatibility
|
|
985
|
+
- Optional adoption — add types where they help
|
|
986
|
+
- Zero runtime cost — types are compile-time only
|
|
987
|
+
- Minimal syntax — Rip stays Rip
|
|
988
|
+
|
|
989
|
+
> **Static typing as a discipline, not a mandate.**
|
|
990
|
+
|
|
991
|
+
---
|
|
992
|
+
|
|
993
|
+
# 16. Quick Reference
|
|
994
|
+
|
|
995
|
+
## Syntax Cheat Sheet
|
|
996
|
+
|
|
997
|
+
```coffee
|
|
998
|
+
# ═══════════════════════════════════════════════════════════
|
|
999
|
+
# TYPE ANNOTATIONS (::)
|
|
1000
|
+
# ═══════════════════════════════════════════════════════════
|
|
1001
|
+
|
|
1002
|
+
# Variables
|
|
1003
|
+
count:: number = 0
|
|
1004
|
+
name:: string = "Rip"
|
|
1005
|
+
items:: string[] = []
|
|
1006
|
+
|
|
1007
|
+
# Constants
|
|
1008
|
+
MAX:: number =! 100
|
|
1009
|
+
|
|
1010
|
+
# Reactive state
|
|
1011
|
+
count:: number := 0
|
|
1012
|
+
doubled:: number ~= count * 2
|
|
1013
|
+
|
|
1014
|
+
# Function parameters and return
|
|
1015
|
+
def greet(name:: string):: string
|
|
1016
|
+
"Hello, #{name}!"
|
|
1017
|
+
|
|
1018
|
+
# ═══════════════════════════════════════════════════════════
|
|
1019
|
+
# TYPE ALIASES (::=)
|
|
1020
|
+
# ═══════════════════════════════════════════════════════════
|
|
1021
|
+
|
|
1022
|
+
# Simple alias
|
|
1023
|
+
ID ::= number
|
|
1024
|
+
|
|
1025
|
+
# Union (inline)
|
|
1026
|
+
Status ::= "pending" | "active" | "done"
|
|
1027
|
+
|
|
1028
|
+
# Union (block - preferred)
|
|
1029
|
+
HttpMethod ::=
|
|
1030
|
+
| "GET"
|
|
1031
|
+
| "POST"
|
|
1032
|
+
| "PUT"
|
|
1033
|
+
| "DELETE"
|
|
1034
|
+
|
|
1035
|
+
# Structural type
|
|
1036
|
+
User ::= type
|
|
1037
|
+
id: number
|
|
1038
|
+
name: string
|
|
1039
|
+
email?: string
|
|
1040
|
+
|
|
1041
|
+
# Function type
|
|
1042
|
+
Handler ::= (req:: Request) -> Response
|
|
1043
|
+
|
|
1044
|
+
# Generic type
|
|
1045
|
+
Container<T> ::= type
|
|
1046
|
+
value: T
|
|
1047
|
+
|
|
1048
|
+
# ═══════════════════════════════════════════════════════════
|
|
1049
|
+
# OPTIONALITY MODIFIERS
|
|
1050
|
+
# ═══════════════════════════════════════════════════════════
|
|
1051
|
+
|
|
1052
|
+
email:: string? # T | undefined
|
|
1053
|
+
middle:: string?? # T | null | undefined
|
|
1054
|
+
id:: ID! # NonNullable<T>
|
|
1055
|
+
|
|
1056
|
+
# ═══════════════════════════════════════════════════════════
|
|
1057
|
+
# GENERICS
|
|
1058
|
+
# ═══════════════════════════════════════════════════════════
|
|
1059
|
+
|
|
1060
|
+
def identity<T>(x:: T):: T
|
|
1061
|
+
x
|
|
1062
|
+
|
|
1063
|
+
def map<T, U>(arr:: T[], fn:: (x:: T) -> U):: U[]
|
|
1064
|
+
arr.map(fn)
|
|
1065
|
+
|
|
1066
|
+
# With constraints
|
|
1067
|
+
def merge<T extends object>(a:: T, b:: T):: T
|
|
1068
|
+
{...a, ...b}
|
|
1069
|
+
|
|
1070
|
+
# ═══════════════════════════════════════════════════════════
|
|
1071
|
+
# INTERFACES
|
|
1072
|
+
# ═══════════════════════════════════════════════════════════
|
|
1073
|
+
|
|
1074
|
+
interface Animal
|
|
1075
|
+
name: string
|
|
1076
|
+
|
|
1077
|
+
interface Dog extends Animal
|
|
1078
|
+
breed: string
|
|
1079
|
+
|
|
1080
|
+
# ═══════════════════════════════════════════════════════════
|
|
1081
|
+
# ENUMS (use sparingly)
|
|
1082
|
+
# ═══════════════════════════════════════════════════════════
|
|
1083
|
+
|
|
1084
|
+
enum Status
|
|
1085
|
+
pending
|
|
1086
|
+
active
|
|
1087
|
+
done
|
|
1088
|
+
|
|
1089
|
+
enum HttpCode
|
|
1090
|
+
ok = 200
|
|
1091
|
+
notFound = 404
|
|
1092
|
+
```
|
|
1093
|
+
|
|
1094
|
+
## Comparison: Rip vs TypeScript vs CoffeeScript
|
|
1095
|
+
|
|
1096
|
+
| Feature | Rip | TypeScript | CoffeeScript |
|
|
1097
|
+
|---------|-----|------------|--------------|
|
|
1098
|
+
| Type annotations | `x:: T` | `x: T` | N/A |
|
|
1099
|
+
| Type aliases | `T ::= ...` | `type T = ...` | N/A |
|
|
1100
|
+
| Optional type | `T?` | `T \| undefined` | N/A |
|
|
1101
|
+
| Nullable | `T??` | `T \| null \| undefined` | N/A |
|
|
1102
|
+
| Non-nullable | `T!` | `NonNullable<T>` | N/A |
|
|
1103
|
+
| Structural types | `type` block | `{ ... }` | N/A |
|
|
1104
|
+
| Block unions | `\| "a" \| "b"` | Same | N/A |
|
|
1105
|
+
| Types required | No | Configurable | N/A |
|
|
1106
|
+
| Runtime cost | Zero | Zero | N/A |
|
|
1107
|
+
|
|
1108
|
+
## Project Configuration
|
|
1109
|
+
|
|
1110
|
+
```json
|
|
1111
|
+
// package.json
|
|
1112
|
+
{
|
|
1113
|
+
"rip": {
|
|
1114
|
+
"types": "emit" // "off" | "emit" | "check"
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
```
|
|
1118
|
+
|
|
1119
|
+
## File Directives
|
|
1120
|
+
|
|
1121
|
+
```coffee
|
|
1122
|
+
# @types off — Ignore types in this file
|
|
1123
|
+
# @types emit — Parse and emit .d.ts
|
|
1124
|
+
# @types check — Full TypeScript checking
|
|
1125
|
+
```
|
|
1126
|
+
|
|
1127
|
+
---
|
|
1128
|
+
|
|
1129
|
+
**See Also:**
|
|
1130
|
+
- [README.md](README.md) — Language overview
|
|
1131
|
+
- [docs/GUIDE.md](docs/GUIDE.md) — Language guide
|
|
1132
|
+
- [docs/REACTIVITY.md](docs/REACTIVITY.md) — Reactive system details
|