You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
`as const` is a powerful assertion that freezes an entire object or array, converting all types to their literal equivalents and marking everything as readonly:
355
+
356
+
```typescript
357
+
// Without as const: { status: string }
358
+
settings1= { status: 'active' }
359
+
360
+
// With as const: { readonly status: 'active' }
361
+
settings2= { status: 'active' } asconst
362
+
```
363
+
364
+
This is particularly useful for creating type-safe enums and configuration constants:
The `as const` assertion freezes an object or array to use literal types instead of general types. This is useful for creating immutable configuration objects and type-safe enums:
321
+
322
+
```typescript
323
+
// Without as const: inferred as { name: string, level: number }
324
+
settings= { name: 'default', level: 1 }
325
+
326
+
// With as const: inferred as { readonly name: 'default', readonly level: 1 }
Copy file name to clipboardExpand all lines: docs/TYPESCRIPT_GAP_ANALYSIS.md
+21-20Lines changed: 21 additions & 20 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -28,6 +28,8 @@ This document tracks which TypeScript type-system features are present in Blop a
28
28
| Dead code detection (unreachable code after `return` / `throw`) |`statements.js` — warns on code after an unconditional early exit |
29
29
|**Tuple types (`[string, number]`)**|`TupleType` — see design notes below |
30
30
|**`as` type assertion**| Grammar reuses the `as` keyword; inference stamps asserted type; backend erases the annotation |
31
+
|**`as const` / const assertions**|`{ x: 1 } as const` — freeze inferred types to literal equivalents; recursively convert to `LiteralType`|
32
+
|**`readonly` modifier**|`readonly name: string`, `readonly T[]` — `readonly` flag on `ObjectType` properties and `ArrayType`; errors on assignment |
31
33
|**User-defined type predicates (`x is T`)**|`PredicateType` — see design notes below |
32
34
|**`keyof` operator**|`KeyofType` — see design notes below |
33
35
|**Class member type annotations**|`classMembers.test.js` — member type annotations, method signatures, and `this` inference all work |
@@ -50,45 +52,44 @@ These are self-contained, add immediate practical value, and do not require majo
50
52
51
53
| # | Feature | TS example | Blocked by | Notes |
52
54
|---|---|---|---|---|
53
-
| 1 |**`as const` / const assertions**|`{ x: 1 } as const`| — | Freeze all inferred types to their literal equivalents. Reuse `as` grammar; add a `constAssertion` flag. Recursively convert `number` → `LiteralType(n)`, `string` → `LiteralType(s)`, turn object values into readonly literals. |
54
-
| 2 |**`readonly` modifier**|`readonly name: string`, `readonly T[]`| — | Add a `readonly` flag in `ObjectType` properties and `ArrayType`. Emit a type error on assignment. Grammar: add `readonly` as an optional prefix on property annotations and array type syntax. No new `Type` subclass needed. |
55
-
| 3 |**`satisfies` operator**|`expr satisfies T`|`as` infrastructure | Like `as` but with a compatibility check: error if the expression type is not assignable to `T`. Reuse `parseTypeExpression` + `isCompatibleWith`; keep the original inferred type (not the asserted one) for downstream inference. A strict complement to `as`. |
56
-
| 4 |**Exhaustiveness checking**|`switch (x) { … }` + `never` narrowing | Type narrowing | After all branches of an `if/else` or `switch` have been handled, the remaining type should reduce to `never`. Emit a warning if a `never`-typed value is used (e.g. returned). Extend the checking phase's narrowing logic in `statements.js`. |
55
+
| 1 |**`satisfies` operator**|`expr satisfies T`|`as` infrastructure | Like `as` but with a compatibility check: error if the expression type is not assignable to `T`. Reuse `parseTypeExpression` + `isCompatibleWith`; keep the original inferred type (not the asserted one) for downstream inference. A strict complement to `as`. |
56
+
| 2 |**Exhaustiveness checking**|`switch (x) { … }` + `never` narrowing | Type narrowing | After all branches of an `if/else` or `switch` have been handled, the remaining type should reduce to `never`. Emit a warning if a `never`-typed value is used (e.g. returned). Extend the checking phase's narrowing logic in `statements.js`. |
57
57
58
58
### Tier 2 — Medium complexity (unlock utility types)
59
59
60
60
These require new `Type` subclasses but have well-understood semantics.
61
61
62
62
| # | Feature | TS example | Blocked by | Notes |
63
63
|---|---|---|---|---|
64
-
|6|**Mapped types**|`{ [K in keyof T]: T[K] }`|`keyof` ✓ | New `MappedType` class with `keyParam`, `sourceType`, `valueExpr`. Resolution: expand `keyof sourceType`, bind `K` to each key, evaluate `valueExpr`. Unlocks `Partial<T>`, `Required<T>`, `Pick<T,K>`, `Omit<T,K>` as standard library aliases. |
65
-
|7|**Conditional types**|`T extends U ? X : Y`| New `ConditionalType`| New `ConditionalType` class with `checkType`, `extendsType`, `trueType`, `falseType`. Resolution: check if `checkType` is assignable to `extendsType`; pick branch. Enables `ReturnType<F>`, `Parameters<F>`, `NonNullable<T>`. |
66
-
|8|**`infer` keyword**|`T extends Array<infer E>`| Conditional types | Binding mechanism inside the `extendsType` of a conditional. The `infer` variable is in scope only in the true branch. |
67
-
|9|**`Partial<T>`, `Required<T>`, `Pick<T,K>`, `Omit<T,K>`**| — | Mapped types | Once mapped types land, these become simple type alias definitions in `stdlib.js`. |
68
-
|10|**`ReturnType<F>`, `Parameters<F>`**| — | Conditional + `infer`|`ReturnType<F>` = `F extends (...args: any[]) => infer R ? R : never`. |
69
-
|11|**Function overloads**| Multiple call signatures | — |`FunctionType[]` per symbol. At call sites: find the first compatible overload. Grammar: a block of signature declarations before the implementation body. |
70
-
|12|**Template literal types**|`` `prefix-${string}` ``| New `TemplateLiteralType`|`TemplateLiteralType` with `parts: Array<string \| Type>`. Evaluates against string literal types; widens to `string` otherwise. |
64
+
|3|**Mapped types**|`{ [K in keyof T]: T[K] }`|`keyof` ✓ | New `MappedType` class with `keyParam`, `sourceType`, `valueExpr`. Resolution: expand `keyof sourceType`, bind `K` to each key, evaluate `valueExpr`. Unlocks `Partial<T>`, `Required<T>`, `Pick<T,K>`, `Omit<T,K>` as standard library aliases. |
65
+
|4|**Conditional types**|`T extends U ? X : Y`| New `ConditionalType`| New `ConditionalType` class with `checkType`, `extendsType`, `trueType`, `falseType`. Resolution: check if `checkType` is assignable to `extendsType`; pick branch. Enables `ReturnType<F>`, `Parameters<F>`, `NonNullable<T>`. |
66
+
|5|**`infer` keyword**|`T extends Array<infer E>`| Conditional types | Binding mechanism inside the `extendsType` of a conditional. The `infer` variable is in scope only in the true branch. |
67
+
|6|**`Partial<T>`, `Required<T>`, `Pick<T,K>`, `Omit<T,K>`**| — | Mapped types | Once mapped types land, these become simple type alias definitions in `stdlib.js`. |
68
+
|7|**`ReturnType<F>`, `Parameters<F>`**| — | Conditional + `infer`|`ReturnType<F>` = `F extends (...args: any[]) => infer R ? R : never`. |
69
+
|8|**Function overloads**| Multiple call signatures | — |`FunctionType[]` per symbol. At call sites: find the first compatible overload. Grammar: a block of signature declarations before the implementation body. |
70
+
|9|**Template literal types**|`` `prefix-${string}` ``| New `TemplateLiteralType`|`TemplateLiteralType` with `parts: Array<string \| Type>`. Evaluates against string literal types; widens to `string` otherwise. |
71
71
72
72
### Tier 3 — Advanced / lower immediate impact
73
73
74
+
| # | Feature | TS example | Notes |
74
75
| # | Feature | TS example | Notes |
75
76
|---|---|---|---|
76
-
|13|**`typeof x` in annotation position**|`type T = typeof someVar`| Type query — resolves to the inferred type of a variable. Requires look-up in the scope snapshot at declaration site. |
77
-
|14|**`implements` interface checking**|`class Foo implements IFoo`| Class member annotations are already typed; `implements` would cross-check the class shape against a declared object type at the class-definition node. Straightforward extension of the existing excess-properties check. |
78
-
|15|**Generic constraints**|`K extends keyof T`| Grammar for `extends` on type parameters; enforce in `substituteTypeParams`. `keyof` exists but cannot yet appear as a constraint. |
79
-
|16|**Assertion functions**|`asserts cond`| Grammar + narrowing — analog to `PredicateType`; requires an `AssertionType` class and narrowing in the post-call scope. |
80
-
|17|**Exhaustiveness in discriminated unions**|`switch (tag) { case 'a': … }`| Extension of Tier 1 #5; matches on literal types to peel the union case-by-case. |
81
-
|18|**Declaration / interface merging**| Same-name type aliases | Symbol table change: collect all declarations of a name and merge their shapes. |
82
-
|19|**Variance annotations**|`in`/`out` on generics | New flag on `GenericType`; enforced during `isCompatibleWith` on generic arguments. |
77
+
|10|**`typeof x` in annotation position**|`type T = typeof someVar`| Type query — resolves to the inferred type of a variable. Requires look-up in the scope snapshot at declaration site. |
78
+
|11|**`implements` interface checking**|`class Foo implements IFoo`| Class member annotations are already typed; `implements` would cross-check the class shape against a declared object type at the class-definition node. Straightforward extension of the existing excess-properties check. |
79
+
|12|**Generic constraints**|`K extends keyof T`| Grammar for `extends` on type parameters; enforce in `substituteTypeParams`. `keyof` exists but cannot yet appear as a constraint. |
80
+
|13|**Assertion functions**|`asserts cond`| Grammar + narrowing — analog to `PredicateType`; requires an `AssertionType` class and narrowing in the post-call scope. |
81
+
|14|**Exhaustiveness in discriminated unions**|`switch (tag) { case 'a': … }`| Extension of Tier 1 #2; matches on literal types to peel the union case-by-case. |
82
+
|15|**Declaration / interface merging**| Same-name type aliases | Symbol table change: collect all declarations of a name and merge their shapes. |
83
+
|16|**Variance annotations**|`in`/`out` on generics | New flag on `GenericType`; enforced during `isCompatibleWith` on generic arguments. |
83
84
84
85
---
85
86
86
87
## What Would Move the Needle Most
87
88
88
89
If the goal is maximum practical value for Blop programs written today, the suggested order of attack is:
89
90
90
-
1.**`as const`** — unlocks literal-type patterns everywhere; touches only the `as` infrastructure already in place.
91
-
2.**`readonly`** — adds an immutability safety net; property flag, no new type class.
91
+
1.✅ **`as const`** — unlocks literal-type patterns everywhere; touches only the `as` infrastructure already in place. **DONE as of v1.3.0**.
92
+
2.✅ **`readonly`** — adds an immutability safety net; property flag, no new type class. **DONE as of v1.3.0**.
92
93
3.**`satisfies`** — adds the strict complement to `as`; reuses all type-check infrastructure.
93
94
4.**Exhaustiveness checking** — big DX win for discriminated-union patterns; extends existing dead-code logic.
94
95
5.**Mapped types** — medium effort, high reward: immediately unlocks `Partial`, `Pick`, `Omit`, `Required`.
0 commit comments