deno.land / x / typebox@0.32.21 / changelog / 0.27.0.md

0.27.0

Overview

Revision 0.27.0 adds support for runtime Template Literal Types. This revision does not include any functional breaking changes but does rename some public type aliases. As such this revision requires a minor semver increment.

Contents

Template Literal Types

Revision 0.27.0 adds support for Template Literal types. These types operate as a form of computed TUnion<TLiteral<string>>. TypeBox encodes template literals using a subset of ECMA 262 regular erxpressions which are applied to pattern properties of type string. This encoding enables JSON Schema validators to assert using existing regular expression checks.

TypeScript

TypeScript defines Template Literals using back tick quoted strings which may include embedded union groups.

type T = `option${'A'|'B'}`                          // type T = 'optionA' | 'optionB'

type R = Record<T, string>                           // type R = {
                                                     //   optionA: string
                                                     //   optionB: string
                                                     // }

TypeBox

TypeBox defines Template Literals using the TemplateLiteral function. This function accepts a sequence of TLiteral, TString, TNumber, TInteger and TBigInt which describe a sequence concatenations. The embedded TUnion type defines an option group which can later be expanded into a set of TLiteral<string>. This expansion enables Template Literal types to also be used as Record keys.

const T = Type.TemplateLiteral([                     // const T = {
  Type.Literal('option'),                            //   pattern: '^option(A|B)$',
  Type.Union([                                       //   type: 'string'
    Type.Literal('A'),                               // }
    Type.Literal('B')
  ])
])

const R = Type.Record(T, Type.String())              // const R = {
                                                     //   type: 'object',
                                                     //   required: ['optionA', 'optionB'],
                                                     //   properties: {
                                                     //     optionA: {
                                                     //       type: 'string'
                                                     //     },
                                                     //     optionB: {
                                                     //       type: 'string'
                                                     //     }
                                                     //   }
                                                     // }

type T = Static<typeof T>                            // type T = 'optionA' | 'optionB'

type R = Static<typeof R>                            // type R = {
                                                     //   optionA: string
                                                     //   optionB: string
                                                     // }

TemplateLiteralParser

Template Literal types are encoded as string patterns. Because these types also need to act as composable union types, Revision 0.27.0 includes an expression parser / generator system specifically for regular expressions. This system is used during composition to allow templates to compose with other types, but can also be used in isolation to generate string sequences for the supported expression grammar. This functionality may be provided as standard on the Value.* sub module in subsequent revisions.

The following generates a 8-bit binary sequence for the given expression.

import { TemplateLiteralParser, TemplateLiteralGenerator, TemplateLiteralFinite } from '@sinclair/typebox'

const Bit  = `(0|1)`                                              // bit union
const Byte = `${Bit}${Bit}${Bit}${Bit}${Bit}${Bit}${Bit}${Bit}`   // byte sequence

const E = TemplateLiteralParser.Parse(Byte)                       // parsed expression tree
const F = TemplateLiteralFinite.Check(E)                          // is the expression finite?
const S = [...TemplateLiteralGenerator.Generate(E)]               // generate sequence
         
// const S = [                                                    // computed sequence
//     '00000000', '00000001', '00000010', '00000011', '00000100',
//     '00000101', '00000110', '00000111', '00001000', '00001001',
//     '00001010', '00001011', '00001100', '00001101', '00001110',
//     '00001111', '00010000', '00010001', '00010010', '00010011',
//     '00010100', '00010101', '00010110', '00010111', '00011000',
//     '00011001', '00011010', '00011011', '00011100', '00011101',
//     '00011110', '00011111', '00100000', '00100001', '00100010',
//     '00100011', '00100100', '00100101', '00100110', '00100111',
//     '00101000', '00101001', '00101010', '00101011', '00101100',
//     '00101101', '00101110', '00101111', '00110000', '00110001',
//     '00110010', '00110011', '00110100', '00110101', '00110110',
//     '00110111', '00111000', '00111001', '00111010', '00111011',
//     '00111100', '00111101', '00111110', '00111111', '01000000',
//     '01000001', '01000010', '01000011', '01000100', '01000101',
//     '01000110', '01000111', '01001000', '01001001', '01001010',
//     '01001011', '01001100', '01001101', '01001110', '01001111',
//     '01010000', '01010001', '01010010', '01010011', '01010100',
//     '01010101', '01010110', '01010111', '01011000', '01011001',
//     '01011010', '01011011', '01011100', '01011101', '01011110',
//     '01011111', '01100000', '01100001', '01100010', '01100011',
//     ... 156 more items
//   ]

Workbench

To assist with TypeScript alignment and to prototype new features. A new web based compiler tool has been written that allows interactive cross compiling between TypeScript and TypeBox. This tool will be enhanced seperately from the TypeBox project, but can be used to quickly generate TypeBox type definitions from existing TypeScript types.

TypeBox Workbench Application

TypeBox Workbench Project

Breaking Changes

The following are breaking changes in Revision 0.27.0

TSelf renamed to TThis

This rename is to align with TypeScript interfaces. Unlike type aliases, TypeScript interface types include a implicit this type. This change relates specifically to TypeBox's current Recursive type which passes the TThis parameter via callback. The TThis parameter can be seen as analogous to the implicit TypeScript interface this.

Consider the following.

// type T = { id: string, nodes: this[] }        // error: no implicit this

interface Node {                                 // ok: this is implicit for interfaces
  id: string, 
  nodes: this[] 
}  

const T = Type.Recursive(This =>                 // `This` === implicit 'this' for interface
  Type.Object({                                  //
    id: Type.String(),                           // Should `Recursive` be renamed to `Interface`?
    nodes: Type.Array(This)
  })
)

Future revisions may rename Recurisve to Interface, but for now, just the TSelf has been renamed.

typebox

Version Info

Tagged at
3 weeks ago