tjs-lang 0.2.0
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/CONTEXT.md +594 -0
- package/LICENSE +190 -0
- package/README.md +220 -0
- package/bin/benchmarks.ts +351 -0
- package/bin/dev.ts +205 -0
- package/bin/docs.js +170 -0
- package/bin/install-cursor.sh +71 -0
- package/bin/install-vscode.sh +71 -0
- package/bin/select-local-models.d.ts +1 -0
- package/bin/select-local-models.js +28 -0
- package/bin/select-local-models.ts +31 -0
- package/demo/autocomplete.test.ts +232 -0
- package/demo/docs.json +186 -0
- package/demo/examples.test.ts +598 -0
- package/demo/index.html +91 -0
- package/demo/src/autocomplete.ts +482 -0
- package/demo/src/capabilities.ts +859 -0
- package/demo/src/demo-nav.ts +2097 -0
- package/demo/src/examples.test.ts +161 -0
- package/demo/src/examples.ts +476 -0
- package/demo/src/imports.test.ts +196 -0
- package/demo/src/imports.ts +421 -0
- package/demo/src/index.ts +639 -0
- package/demo/src/module-store.ts +635 -0
- package/demo/src/module-sw.ts +132 -0
- package/demo/src/playground.ts +949 -0
- package/demo/src/service-host.ts +389 -0
- package/demo/src/settings.ts +440 -0
- package/demo/src/style.ts +280 -0
- package/demo/src/tjs-playground.ts +1605 -0
- package/demo/src/ts-examples.ts +478 -0
- package/demo/src/ts-playground.ts +1092 -0
- package/demo/static/favicon.svg +30 -0
- package/demo/static/photo-1.jpg +0 -0
- package/demo/static/photo-2.jpg +0 -0
- package/demo/static/texts/ai-history.txt +9 -0
- package/demo/static/texts/coffee-origins.txt +9 -0
- package/demo/static/texts/renewable-energy.txt +9 -0
- package/dist/index.js +256 -0
- package/dist/index.js.map +37 -0
- package/dist/tjs-batteries.js +4 -0
- package/dist/tjs-batteries.js.map +15 -0
- package/dist/tjs-full.js +256 -0
- package/dist/tjs-full.js.map +37 -0
- package/dist/tjs-transpiler.js +220 -0
- package/dist/tjs-transpiler.js.map +21 -0
- package/dist/tjs-vm.js +4 -0
- package/dist/tjs-vm.js.map +14 -0
- package/docs/CNAME +1 -0
- package/docs/favicon.svg +30 -0
- package/docs/index.html +91 -0
- package/docs/index.js +10468 -0
- package/docs/index.js.map +92 -0
- package/docs/photo-1.jpg +0 -0
- package/docs/photo-1.webp +0 -0
- package/docs/photo-2.jpg +0 -0
- package/docs/photo-2.webp +0 -0
- package/docs/texts/ai-history.txt +9 -0
- package/docs/texts/coffee-origins.txt +9 -0
- package/docs/texts/renewable-energy.txt +9 -0
- package/docs/tjs-lang.svg +31 -0
- package/docs/tosijs-agent.svg +31 -0
- package/editors/README.md +325 -0
- package/editors/ace/ajs-mode.js +328 -0
- package/editors/ace/ajs-mode.ts +269 -0
- package/editors/ajs-syntax.ts +212 -0
- package/editors/build-grammars.ts +510 -0
- package/editors/codemirror/ajs-language.js +287 -0
- package/editors/codemirror/ajs-language.ts +1447 -0
- package/editors/codemirror/autocomplete.test.ts +531 -0
- package/editors/codemirror/component.ts +404 -0
- package/editors/monaco/ajs-monarch.js +243 -0
- package/editors/monaco/ajs-monarch.ts +225 -0
- package/editors/tjs-syntax.ts +115 -0
- package/editors/vscode/language-configuration.json +37 -0
- package/editors/vscode/package.json +65 -0
- package/editors/vscode/syntaxes/ajs-injection.tmLanguage.json +107 -0
- package/editors/vscode/syntaxes/ajs.tmLanguage.json +252 -0
- package/editors/vscode/syntaxes/tjs.tmLanguage.json +333 -0
- package/package.json +83 -0
- package/src/cli/commands/check.ts +41 -0
- package/src/cli/commands/convert.ts +133 -0
- package/src/cli/commands/emit.ts +260 -0
- package/src/cli/commands/run.ts +68 -0
- package/src/cli/commands/test.ts +194 -0
- package/src/cli/commands/types.ts +20 -0
- package/src/cli/create-app.ts +236 -0
- package/src/cli/playground.ts +250 -0
- package/src/cli/tjs.ts +166 -0
- package/src/cli/tjsx.ts +160 -0
- package/tjs-lang.svg +31 -0
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript Examples
|
|
3
|
+
*
|
|
4
|
+
* These examples demonstrate the TS -> TJS -> JS pipeline.
|
|
5
|
+
* They are written in ACTUAL TypeScript syntax (not TJS).
|
|
6
|
+
* The playground shows:
|
|
7
|
+
* - TS input (editable)
|
|
8
|
+
* - TJS intermediate (read-only)
|
|
9
|
+
* - JS output with __tjs metadata
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export interface TSExample {
|
|
13
|
+
name: string
|
|
14
|
+
description: string
|
|
15
|
+
code: string
|
|
16
|
+
group: 'intro' | 'validation' | 'patterns' | 'advanced'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const tsExamples: TSExample[] = [
|
|
20
|
+
// ═══════════════════════════════════════════════════════════════
|
|
21
|
+
// INTRO: Basic TypeScript to TJS examples
|
|
22
|
+
// ═══════════════════════════════════════════════════════════════
|
|
23
|
+
{
|
|
24
|
+
name: 'Hello TypeScript',
|
|
25
|
+
description: 'See how TypeScript types become TJS example-based types',
|
|
26
|
+
group: 'intro',
|
|
27
|
+
code: `// TypeScript: Types are compile-time only
|
|
28
|
+
// TJS: Types become runtime validation!
|
|
29
|
+
|
|
30
|
+
function greet(name: string): string {
|
|
31
|
+
return \`Hello, \${name}!\`
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// This works - correct type
|
|
35
|
+
console.log(greet('World'))
|
|
36
|
+
|
|
37
|
+
// In pure TS, this would crash at runtime
|
|
38
|
+
// In TJS, you get a clean error object
|
|
39
|
+
console.log('Bad call result:', greet(42 as any))
|
|
40
|
+
`,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: 'Multiple Functions',
|
|
44
|
+
description: 'Multiple functions transpile correctly',
|
|
45
|
+
group: 'intro',
|
|
46
|
+
code: `// Multiple functions in one file
|
|
47
|
+
|
|
48
|
+
function add(a: number, b: number): number {
|
|
49
|
+
return a + b
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function multiply(a: number, b: number): number {
|
|
53
|
+
return a * b
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function greet(name: string, excited?: boolean): string {
|
|
57
|
+
return excited ? \`Hello, \${name}!\` : \`Hello, \${name}\`
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Test them all
|
|
61
|
+
console.log('add(2, 3) =', add(2, 3))
|
|
62
|
+
console.log('multiply(4, 5) =', multiply(4, 5))
|
|
63
|
+
console.log('greet("World") =', greet('World'))
|
|
64
|
+
console.log('greet("World", true) =', greet('World', true))
|
|
65
|
+
`,
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: 'Type Transformation',
|
|
69
|
+
description: 'See how TypeScript types become TJS examples',
|
|
70
|
+
group: 'intro',
|
|
71
|
+
code: `// TypeScript type syntax -> TJS example syntax
|
|
72
|
+
//
|
|
73
|
+
// TypeScript: TJS:
|
|
74
|
+
// name: string -> name: ''
|
|
75
|
+
// count: number -> count: 0
|
|
76
|
+
// flag: boolean -> flag: true
|
|
77
|
+
// items: string[] -> items: ['']
|
|
78
|
+
// ): string -> -> ''
|
|
79
|
+
|
|
80
|
+
function processData(
|
|
81
|
+
name: string,
|
|
82
|
+
count: number,
|
|
83
|
+
active: boolean,
|
|
84
|
+
tags: string[]
|
|
85
|
+
): string {
|
|
86
|
+
return \`\${name}: \${count} items, active=\${active}, tags=[\${tags.join(', ')}]\`
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
console.log(processData('Test', 42, true, ['a', 'b', 'c']))
|
|
90
|
+
`,
|
|
91
|
+
},
|
|
92
|
+
|
|
93
|
+
// ═══════════════════════════════════════════════════════════════
|
|
94
|
+
// VALIDATION: Runtime type checking from TS types
|
|
95
|
+
// ═══════════════════════════════════════════════════════════════
|
|
96
|
+
{
|
|
97
|
+
name: 'Embedded Tests',
|
|
98
|
+
description: 'Write tests in comments that survive TypeScript compilation',
|
|
99
|
+
group: 'validation',
|
|
100
|
+
code: `// Embedded tests live inside /*test ... */ comments
|
|
101
|
+
// These survive TypeScript compilation and are extracted by TJS!
|
|
102
|
+
|
|
103
|
+
function add(a: number, b: number): number {
|
|
104
|
+
return a + b
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/*test 'adds positive numbers' {
|
|
108
|
+
expect(add(2, 3)).toBe(5)
|
|
109
|
+
}*/
|
|
110
|
+
|
|
111
|
+
/*test 'adds negative numbers' {
|
|
112
|
+
expect(add(-1, -2)).toBe(-3)
|
|
113
|
+
}*/
|
|
114
|
+
|
|
115
|
+
/*test 'handles zero' {
|
|
116
|
+
expect(add(0, 5)).toBe(5)
|
|
117
|
+
expect(add(5, 0)).toBe(5)
|
|
118
|
+
}*/
|
|
119
|
+
|
|
120
|
+
function multiply(a: number, b: number): number {
|
|
121
|
+
return a * b
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/*test 'multiplies numbers' {
|
|
125
|
+
expect(multiply(3, 4)).toBe(12)
|
|
126
|
+
expect(multiply(-2, 3)).toBe(-6)
|
|
127
|
+
}*/
|
|
128
|
+
|
|
129
|
+
// Try it: Check the "Tests" tab to see results!
|
|
130
|
+
// These tests run at transpile time, giving you immediate feedback.
|
|
131
|
+
|
|
132
|
+
console.log('add(10, 20) =', add(10, 20))
|
|
133
|
+
console.log('multiply(5, 6) =', multiply(5, 6))
|
|
134
|
+
`,
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
name: 'Runtime Validation',
|
|
138
|
+
description: 'TypeScript types work at RUNTIME, not just compile time',
|
|
139
|
+
group: 'validation',
|
|
140
|
+
code: `// The key insight: TS types become runtime checks
|
|
141
|
+
|
|
142
|
+
function divide(a: number, b: number): number {
|
|
143
|
+
if (b === 0) return NaN
|
|
144
|
+
return a / b
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Valid calls work normally
|
|
148
|
+
console.log('10 / 2 =', divide(10, 2))
|
|
149
|
+
console.log('10 / 0 =', divide(10, 0))
|
|
150
|
+
|
|
151
|
+
// Invalid calls return error objects (not crashes!)
|
|
152
|
+
const badResult = divide('ten' as any, 2)
|
|
153
|
+
console.log('divide("ten", 2) =', badResult)
|
|
154
|
+
|
|
155
|
+
if (badResult && badResult.$error) {
|
|
156
|
+
console.log(' ^ This is a validation error, not a crash!')
|
|
157
|
+
}
|
|
158
|
+
`,
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
name: 'Object Validation',
|
|
162
|
+
description: 'Object types are validated at runtime',
|
|
163
|
+
group: 'validation',
|
|
164
|
+
code: `// Object types become runtime checks
|
|
165
|
+
|
|
166
|
+
interface User {
|
|
167
|
+
name: string
|
|
168
|
+
age: number
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function greetUser(user: User): string {
|
|
172
|
+
return \`Hello, \${user.name}! You are \${user.age} years old.\`
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Valid object works
|
|
176
|
+
const alice = { name: 'Alice', age: 30 }
|
|
177
|
+
console.log(greetUser(alice))
|
|
178
|
+
|
|
179
|
+
// Non-object fails validation
|
|
180
|
+
const badInput = greetUser('not an object' as any)
|
|
181
|
+
console.log('String input:', badInput)
|
|
182
|
+
|
|
183
|
+
// Note: Current validation checks type (object vs primitive)
|
|
184
|
+
// Deep property validation is a future enhancement
|
|
185
|
+
`,
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
name: 'Optional Parameters',
|
|
189
|
+
description: 'Optional params work in TS and TJS',
|
|
190
|
+
group: 'validation',
|
|
191
|
+
code: `// Optional parameters: TS ? syntax or default values
|
|
192
|
+
|
|
193
|
+
function createGreeting(
|
|
194
|
+
name: string,
|
|
195
|
+
greeting?: string,
|
|
196
|
+
punctuation: string = '!'
|
|
197
|
+
): string {
|
|
198
|
+
const g = greeting ?? 'Hello'
|
|
199
|
+
return \`\${g}, \${name}\${punctuation}\`
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// All these work
|
|
203
|
+
console.log(createGreeting('World'))
|
|
204
|
+
console.log(createGreeting('World', 'Hi'))
|
|
205
|
+
console.log(createGreeting('World', 'Hey', '...'))
|
|
206
|
+
|
|
207
|
+
// Check the metadata
|
|
208
|
+
console.log('\\nFunction metadata:')
|
|
209
|
+
console.log(' name: required')
|
|
210
|
+
console.log(' greeting: optional')
|
|
211
|
+
console.log(' punctuation: optional with default "!"')
|
|
212
|
+
`,
|
|
213
|
+
},
|
|
214
|
+
|
|
215
|
+
// ═══════════════════════════════════════════════════════════════
|
|
216
|
+
// PATTERNS: Common TypeScript patterns
|
|
217
|
+
// ═══════════════════════════════════════════════════════════════
|
|
218
|
+
{
|
|
219
|
+
name: 'Array Operations',
|
|
220
|
+
description: 'Array types flow through the pipeline',
|
|
221
|
+
group: 'patterns',
|
|
222
|
+
code: `// Array types are preserved
|
|
223
|
+
|
|
224
|
+
function sum(numbers: number[]): number {
|
|
225
|
+
return numbers.reduce((a, b) => a + b, 0)
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function average(numbers: number[]): number {
|
|
229
|
+
if (numbers.length === 0) return 0
|
|
230
|
+
return sum(numbers) / numbers.length
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function filterPositive(numbers: number[]): number[] {
|
|
234
|
+
return numbers.filter(n => n > 0)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const data = [-1, 2, -3, 4, 5, -6, 7]
|
|
238
|
+
console.log('Data:', data)
|
|
239
|
+
console.log('Sum:', sum(data))
|
|
240
|
+
console.log('Average:', average(data))
|
|
241
|
+
console.log('Positive only:', filterPositive(data))
|
|
242
|
+
`,
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
name: 'Nested Objects',
|
|
246
|
+
description: 'Nested object types work correctly',
|
|
247
|
+
group: 'patterns',
|
|
248
|
+
code: `// Nested object types
|
|
249
|
+
|
|
250
|
+
interface Address {
|
|
251
|
+
street: string
|
|
252
|
+
city: string
|
|
253
|
+
zip: string
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
interface Person {
|
|
257
|
+
name: string
|
|
258
|
+
address: Address
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function formatAddress(person: Person): string {
|
|
262
|
+
const { name, address } = person
|
|
263
|
+
return \`\${name}\\n\${address.street}\\n\${address.city}, \${address.zip}\`
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const john: Person = {
|
|
267
|
+
name: 'John Doe',
|
|
268
|
+
address: {
|
|
269
|
+
street: '123 Main St',
|
|
270
|
+
city: 'Springfield',
|
|
271
|
+
zip: '12345'
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
console.log(formatAddress(john))
|
|
276
|
+
`,
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
name: 'Union Types',
|
|
280
|
+
description: 'Union types and nullable values',
|
|
281
|
+
group: 'patterns',
|
|
282
|
+
code: `// Union types: T | null, T | undefined
|
|
283
|
+
|
|
284
|
+
function findUser(id: number): string | null {
|
|
285
|
+
// Simulated lookup
|
|
286
|
+
if (id === 1) return 'Alice'
|
|
287
|
+
if (id === 2) return 'Bob'
|
|
288
|
+
return null
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function greetOrWarn(name: string | null): string {
|
|
292
|
+
if (name === null) {
|
|
293
|
+
return 'User not found!'
|
|
294
|
+
}
|
|
295
|
+
return \`Hello, \${name}!\`
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
console.log('Find user 1:', findUser(1))
|
|
299
|
+
console.log('Find user 2:', findUser(2))
|
|
300
|
+
console.log('Find user 99:', findUser(99))
|
|
301
|
+
|
|
302
|
+
console.log('\\nGreet user 1:', greetOrWarn(findUser(1)))
|
|
303
|
+
console.log('Greet user 99:', greetOrWarn(findUser(99)))
|
|
304
|
+
`,
|
|
305
|
+
},
|
|
306
|
+
|
|
307
|
+
// ═══════════════════════════════════════════════════════════════
|
|
308
|
+
// ADVANCED: More complex TypeScript patterns
|
|
309
|
+
// ═══════════════════════════════════════════════════════════════
|
|
310
|
+
{
|
|
311
|
+
name: 'Generic Functions',
|
|
312
|
+
description: 'Generics transpile with warnings (best-effort)',
|
|
313
|
+
group: 'advanced',
|
|
314
|
+
code: `// Generic functions: TJS handles them best-effort
|
|
315
|
+
// Generic type params become 'any' with a warning
|
|
316
|
+
|
|
317
|
+
function identity<T>(value: T): T {
|
|
318
|
+
return value
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function first<T>(items: T[]): T | undefined {
|
|
322
|
+
return items[0]
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function wrap<T>(value: T): { value: T } {
|
|
326
|
+
return { value }
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// These work at runtime
|
|
330
|
+
console.log('identity(42):', identity(42))
|
|
331
|
+
console.log('identity("hello"):', identity('hello'))
|
|
332
|
+
console.log('first([1,2,3]):', first([1, 2, 3]))
|
|
333
|
+
console.log('wrap({ x: 1 }):', wrap({ x: 1 }))
|
|
334
|
+
|
|
335
|
+
// Check the TJS output - you'll see warnings about generic params
|
|
336
|
+
`,
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
name: 'Async Functions',
|
|
340
|
+
description: 'Async/await works naturally',
|
|
341
|
+
group: 'advanced',
|
|
342
|
+
code: `// Async functions work naturally
|
|
343
|
+
// Promise<T> is unwrapped to T in return type
|
|
344
|
+
|
|
345
|
+
async function fetchData(url: string): Promise<string> {
|
|
346
|
+
// Simulated fetch
|
|
347
|
+
await new Promise(r => setTimeout(r, 100))
|
|
348
|
+
return \`Data from \${url}\`
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
async function fetchMultiple(urls: string[]): Promise<string[]> {
|
|
352
|
+
return Promise.all(urls.map(fetchData))
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Run the async functions
|
|
356
|
+
async function main() {
|
|
357
|
+
console.log('Fetching single...')
|
|
358
|
+
const single = await fetchData('/api/users')
|
|
359
|
+
console.log('Result:', single)
|
|
360
|
+
|
|
361
|
+
console.log('\\nFetching multiple...')
|
|
362
|
+
const multiple = await fetchMultiple(['/api/a', '/api/b', '/api/c'])
|
|
363
|
+
console.log('Results:', multiple)
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
main()
|
|
367
|
+
`,
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
name: 'Classes',
|
|
371
|
+
description: 'Classes are supported with metadata',
|
|
372
|
+
group: 'advanced',
|
|
373
|
+
code: `// Classes with typed methods
|
|
374
|
+
|
|
375
|
+
class Calculator {
|
|
376
|
+
private value: number = 0
|
|
377
|
+
|
|
378
|
+
add(n: number): Calculator {
|
|
379
|
+
this.value += n
|
|
380
|
+
return this
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
multiply(n: number): Calculator {
|
|
384
|
+
this.value *= n
|
|
385
|
+
return this
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
getResult(): number {
|
|
389
|
+
return this.value
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
reset(): void {
|
|
393
|
+
this.value = 0
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// Use the class
|
|
398
|
+
const calc = new Calculator()
|
|
399
|
+
const result = calc.add(5).multiply(3).add(10).getResult()
|
|
400
|
+
console.log('5 * 3 + 10 =', result)
|
|
401
|
+
|
|
402
|
+
// Chain of operations
|
|
403
|
+
calc.reset()
|
|
404
|
+
console.log('After reset:', calc.getResult())
|
|
405
|
+
console.log('(2 + 3) * 4 =', calc.add(2).add(3).multiply(4).getResult())
|
|
406
|
+
`,
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
name: 'The Full Picture',
|
|
410
|
+
description:
|
|
411
|
+
'Complete example showing the TS -> TJS -> JS value proposition',
|
|
412
|
+
group: 'advanced',
|
|
413
|
+
code: `/**
|
|
414
|
+
* THE FULL PICTURE
|
|
415
|
+
*
|
|
416
|
+
* TypeScript promises type safety.
|
|
417
|
+
* TJS delivers it at RUNTIME.
|
|
418
|
+
*
|
|
419
|
+
* This is what "TS keeps its promise" means.
|
|
420
|
+
*/
|
|
421
|
+
|
|
422
|
+
// Define your types with standard TypeScript syntax
|
|
423
|
+
interface Product {
|
|
424
|
+
id: number
|
|
425
|
+
name: string
|
|
426
|
+
price: number
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
interface Order {
|
|
430
|
+
products: Product[]
|
|
431
|
+
customer: string
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// Write your business logic
|
|
435
|
+
function calculateTotal(order: Order): number {
|
|
436
|
+
return order.products.reduce((sum, p) => sum + p.price, 0)
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
function validateOrder(order: Order): string | null {
|
|
440
|
+
if (order.products.length === 0) {
|
|
441
|
+
return 'Order must have at least one product'
|
|
442
|
+
}
|
|
443
|
+
if (!order.customer) {
|
|
444
|
+
return 'Customer name is required'
|
|
445
|
+
}
|
|
446
|
+
return null
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function processOrder(order: Order): { success: boolean; total?: number; error?: string } {
|
|
450
|
+
const error = validateOrder(order)
|
|
451
|
+
if (error) {
|
|
452
|
+
return { success: false, error }
|
|
453
|
+
}
|
|
454
|
+
return { success: true, total: calculateTotal(order) }
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Test with valid data
|
|
458
|
+
const validOrder: Order = {
|
|
459
|
+
customer: 'Alice',
|
|
460
|
+
products: [
|
|
461
|
+
{ id: 1, name: 'Widget', price: 9.99 },
|
|
462
|
+
{ id: 2, name: 'Gadget', price: 19.99 }
|
|
463
|
+
]
|
|
464
|
+
}
|
|
465
|
+
console.log('Valid order:', processOrder(validOrder))
|
|
466
|
+
|
|
467
|
+
// Test with invalid data - TypeScript would let this through!
|
|
468
|
+
// But TJS catches it at runtime.
|
|
469
|
+
const badOrder = { customer: 'Bob' } as any // Missing products
|
|
470
|
+
console.log('Bad order:', processOrder(badOrder))
|
|
471
|
+
|
|
472
|
+
// The value proposition:
|
|
473
|
+
// 1. Write normal TypeScript
|
|
474
|
+
// 2. TJS transpiles it with runtime checks
|
|
475
|
+
// 3. Bad data gets caught, not crashed on
|
|
476
|
+
`,
|
|
477
|
+
},
|
|
478
|
+
]
|