-
Notifications
You must be signed in to change notification settings - Fork 166
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
68 changed files
with
2,241 additions
and
1,039 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
## [0.34.0](https://www.npmjs.com/package/@sinclair/typebox/v/0.34.0) | ||
|
||
## Overview | ||
|
||
Revision 0.34.0 represents a significant milestone for the TypeBox project. This update changes how TypeBox manages type references (Ref) and introduces a new Module type to support mutual recursion and self-referencing types. Additionally, it includes a new submodule for parsing TypeScript syntax directly into TypeBox types. | ||
|
||
Please note that this release includes breaking changes to Ref and some deprecations. These updates require a minor semver revision. | ||
|
||
## Contents | ||
|
||
- [Enhancements](#Enhancements) | ||
- [Module Types](#Module-Types) | ||
- [Syntax Types](#Syntax-Types) | ||
- [Breaking Changes](#Breaking-Changes) | ||
- [Ref](#Ref) | ||
- [Deref](#Deref) | ||
- [Strict](#Strict) | ||
|
||
|
||
<a name="Enhancements"></a> | ||
|
||
## Enhancements | ||
|
||
Below are the enhancements introduced in Version 0.34.0. | ||
|
||
<a name="Module-Type"></a> | ||
|
||
### Module Types | ||
|
||
Revision 0.34.0 introduces a new type, called Module. Modules are represented as JSON Schema $def schematics, specifically designed to support both mutual and self-recursive types. This addition resolves a longstanding issue in TypeBox, where complex recursive structures often encountered "definition order" problems, making certain recursive structures difficult to represent cleanly. With Modules, you can now define schematics within a Module context, allowing them to be referenced within the type system through a separate inference operation. | ||
|
||
```typescript | ||
// The following creates a circular recursive type. | ||
|
||
const Module = Type.Module({ | ||
A: Type.Object({ | ||
b: Type.Ref('B') // Ref B: | ||
}), | ||
B: Type.Object({ | ||
c: Type.Ref('C') // Ref C: | ||
}), | ||
C: Type.Object({ | ||
a: Type.Ref('A') // Ref A: | ||
}), | ||
}) | ||
|
||
// Module types must be imported before use. | ||
|
||
const A = Module.Import('A') // const A: TImport<{...}, 'A'> | ||
|
||
type A = Static<typeof A> // type A = { | ||
// b: { | ||
// c: { | ||
// a: { | ||
// b: ... | ||
// } | ||
// } | ||
// } | ||
// } | ||
``` | ||
<a name="Syntax-Types"></a> | ||
### Syntax Types | ||
Revision 0.34.0 introduces a new submodule for parsing TypeScript syntax directly into TypeBox types, implemented both at runtime and within the type system. This feature was made possible through the development of a separate project, [ParseBox](https://github.com/sinclairzx81/parsebox) (MIT-licensed), which provides a symmetric runtime and type-level parsing infrastructure. | ||
As of 0.34.0, Syntax Types are available as an opt-in feature, with the parsing infrastructure adding approximately 10kb (minified) to the existing type builder. With further optimizations, this feature may be elevated to a top-level import in future updates to minimize bundling size. | ||
To use Syntax Types, import them from the `@sinclair/typebox/syntax` path. | ||
```typescript | ||
import { Parse } from '@sinclair/typebox/syntax' | ||
|
||
// All primitive types are supported | ||
|
||
const A = Parse('string') // const A: TString | ||
const B = Parse('number') // const B: TNumber | ||
const C = Parse('boolean') // const C: TBoolean | ||
|
||
// ... Multiline parsing is supported (but comments are not) | ||
|
||
const T = Parse(`{ | ||
x: number | ||
y: number | ||
z: number | ||
}`) | ||
|
||
|
||
// ... Parametertized parsing is supported | ||
const O = Parse({ T }, `T & { w: number }`) // const O: TIntersect<[ | ||
// TObject<{ | ||
// x: TNumber, | ||
// y: TNumber, | ||
// z: TNumber, | ||
// }>, | ||
// TObject<{ | ||
// w: TNumber | ||
// }> | ||
// ]> | ||
|
||
// ... Module parsing is also supported. | ||
|
||
const Math = Parse(`module Math { | ||
export interface X { | ||
x: number | ||
} | ||
export interface Y { | ||
y: number | ||
} | ||
export interface Z { | ||
z: number | ||
} | ||
export interface Vector extends X, Y, Z { | ||
type: 'Vector' | ||
} | ||
}`) | ||
|
||
const Vector = Math.Import('Vector') | ||
``` | ||
|
||
Runtime parsing performance should be quite good; however, static parsing performance could be improved. TypeScript will invoke the parser for each property accessed at design time. Ongoing efforts within the ParseBox project aim to optimize string parsing in TypeScript, with additional research underway into type-level caching strategies within the TypeScript compiler. Additional optimizations will be explored over the course of 0.34.x. | ||
|
||
<a name="Breaking-Changes"></a> | ||
|
||
## Breaking Changes | ||
|
||
The following are the breaking changes in Revision 0.34.0. | ||
|
||
<a name="Ref"></a> | ||
|
||
### Ref | ||
|
||
Revision 0.34.0 introduces a breaking change to Ref, modifying its signature to accept only constant string values. Previously, Ref could accept an existing TypeBox type, provided it had an $id assigned. | ||
|
||
```typescript | ||
|
||
// Revision 0.33.0 | ||
|
||
const T = Type.String({ $id: 'T' }) | ||
|
||
const R = Type.Ref(T) | ||
|
||
type R = Static<typeof R> // type R = string | ||
|
||
// Revision 0.34.0 | ||
|
||
const T = Type.String({ $id: 'T' }) | ||
|
||
const R = Type.Ref('T') | ||
|
||
type R = Static<typeof R> // type R = unknown | ||
|
||
``` | ||
|
||
In Revision 0.34.0, the inferred type for Ref is now unknown. Implementations using the previous version of Ref can switch to Unsafe to type the reference to the target value. | ||
|
||
```typescript | ||
// Revision 0.34.0 | ||
|
||
const T = Type.String({ $id: 'T' }) | ||
|
||
const R = Type.Unsafe<Static<typeof T>>(Type.Ref('T')) | ||
|
||
type R = Static<typeof R> // type R = string | ||
``` | ||
<a name="Deref"></a> | ||
### Deref | ||
Revision 0.34.0 removes the Deref type, which was previously used to dereference schematics. Since the Ref signature has changed from TSchema to string, there is no longer a way to resolve reference types accurately. TypeBox may provide a prototype example of this type upon request. | ||
<a name="Strict"></a> | ||
### Strict | ||
Revision 0.34.0 removes the Strict type from the Type Builder, which was deprecated in version 0.33.8. This type was introduced several years ago in response to a change in Ajv that prohibited unknown keywords. At that time, TypeBox used string property keys for `kind` and `modifier`, which required either Ajv configuration or the use of Strict. These properties have since been updated to Symbol properties, resolving the issues with Ajv. However, the Strict type remained due to some use in ecosystem projects, which has since reduced. | ||
For those who still need Strict, the recommended approach is to use the JSON stringify/parse method outlined in the deprecation notice. | ||
```typescript | ||
/** | ||
* @deprecated `[Json]` Omits compositing symbols from this schema. It is recommended | ||
* to use the JSON parse/stringify to remove compositing symbols if needed. This | ||
* is how Strict works internally. | ||
* | ||
* ```typescript | ||
* JSON.parse(JSON.stringify(Type.String())) | ||
* ``` | ||
*/ | ||
export function Strict<T extends TSchema>(schema: T): TStrict<T> { | ||
return JSON.parse(JSON.stringify(schema)) | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.