# 1.0.0 Migration Guide

## Overview

This document covers upgrading from TypeBox 0.34.x to 1.0. While most of the API surface remains intact for 1.0, there are several key breaking changes that will impact users who integrate deeply with TypeBox infrastructure. The sections below document these changes and detail strategies for upgrading.

## Contents

- [ESM Package](#ESM)
- [Kind, Hint, ReadonlyKind and OptionalKind](#Symbols)
- [Type.Date and Type.Uint8Array](#Globals)
- [Type.Recursive](#Recursive)
- [Type.RegExp](#RegExp)
- [Type.Composite](#Composite)
- [Type.Transform](#Transform)
- [Type.Const](#Const)
- [Type.Pick and Type.Omit](#PickOmit)
- [TypeCompiler](#TypeCompiler)
- [References](#References)
- [FormatRegistry](#FormatRegistry)
- [TypeRegistry](#TypeRegistry)
- [TypeGuard](#TypeGuard)
- [Value.Errors](#Errors)
- [Value.Cast](#Cast)
- [SetErrorFunction](#SetErrorFunction)
- [CustomErrors](#CustomErrors)

<a name="ESM"></a>

## ESM Package

Version 1.0 is published as an ESM-only package. Users will need to ensure their environments support ESM module resolution.

<a name="Symbols"></a>

## Kind, Hint, ReadonlyKind and OptionalKind

Version 1.0 removes the Kind, ReadonlyKind, OptionalKind symbols. These symbols were originally introduced to enable fast type differentiation internal to the library, as well as to solve integration issues with Ajv strict mode.

The use of symbols have proven difficult for users who install multiple versions of TypeBox side by side. This is most notable in frameworks that install one version of TypeBox and where users install another. The removal of symbols will enable multiple version of TypeBox to run side by side without requiring users to pin specific versions via package.json.

Version 1.0 replaces each symbol with non-enumerable `~kind`, `~readonly` and `~optional` properties. Applications that use symbols to reflect TypeBox types will need to update to read these properties instead. 

### Example

0.34.x

```typescript
import { Type, Kind } from '@sinclair/typebox'

const T = Type.String()

if(T[Kind] === 'String') { ... }
```

1.0.0

```typescript
import Type from 'typebox'

const T = Type.String()

if(T['~kind'] === 'String') { ... }

// Consider using guards instead of direct property access.

if(Type.IsString(T)) { ... }
```

<a name="Globals"></a>

## Type.Date and Type.Uint8Array

Version 1.0 removes the Date and Uint8Array types. These types can be created by combining Type.Unsafe with the new Type.Refine type introduced in 1.x.

### Fallback 

[Uint8Array](/example/legacy/uint8array.ts) | [Date](/example/legacy/date.ts)

### Example

The following creates a Date type by combining Unsafe with Refine.

```typescript
import Type from 'typebox'

export type TDate = Type.TUnsafe<globalThis.Date>

export function Date(): TDate {
  return Type.Refine(Type.Unsafe<globalThis.Date>({ type: 'Date' }), 
    value => value instanceof globalThis.Date,
    _value => 'Expected Date')
}
```

<a name="Recursive"></a>

## Type.Recursive

Version 1.0 removes the Recursive type. This type has been replaced with a new Cyclic type which supports both singular and mutual recursive types.

### Fallback

[Recursive](/example/legacy/recursive.ts)

### Example

0.34.x

```typescript
const Node = Type.Recursive(This => Type.Object({
  id: Type.Number(),
  nodes: Type.Array(This)
}))
```

1.0.0

```typescript
const Node = Type.Cyclic({
  Node: Type.Object({
    id: Type.Number(),
    nodes: Type.Array(Type.Ref('Node'))
  })
}, 'Node')
```

<a name="RegExp"></a>

## Type.RegExp

Version 1.0 removes the RegExp type. TypeBox now allows regular expressions to be passed via `pattern` on String types.

### Fallback

[RegExp](/example/legacy/regexp.ts)

### Example

0.34.x

```typescript
const T = Type.RegExp(/abc/i)
```

1.0.0

```typescript
const T = Type.String({ pattern: /abc/i })
```

<a name="Composite"></a>

## Type.Composite

Version 1.0 removes the Composite type. This type has been replaced by the Interface and Evaluate types. 

### Fallback

[Composite](/example/legacy/composite.ts)

### Example

0.34.x

```typescript
const A = Type.Object({ a: Type.Number() })
const B = Type.Object({ b: Type.Number() })
const C = Type.Composite([A, B])
```

1.0.0

```typescript
// Composite with Interface and Heritage
const A = Type.Object({ a: Type.Number() })
const B = Type.Object({ b: Type.Number() })
const C = Type.Interface([A, B], { c: Type.Number() }) // const C: TObject<{
                                                       //   a: TNumber,
                                                       //   b: TNumber,
                                                       //   c: TNumber
                                                       // }> 

// Composite with Evaluate
const A = Type.Object({ a: Type.Number() })
const B = Type.Object({ b: Type.Number() })
const C = Type.Object({ c: Type.Number() })
const T = Type.Evaluate(Type.Intersect([A, B, C]))     // const T: TObject<{
                                                       //   a: TNumber,
                                                       //   b: TNumber,
                                                       //   c: TNumber
                                                       // }> 
```

<a name="Transform"></a>

## Type.Transform

The Transform type has been renamed to Codec. This change better reflects the distinction between bi-directional vs uni-directional transformation; where 1.0 adds support for uni-directional transforms.

### Fallback

[Transform](/example/legacy/transform.ts)

### Example

0.34.x

```typescript
const NumberToString = Type.Transform(Type.Number())
  .Decode(value => value.toString())
  .Encode(value => parseFloat(value))

```

1.0.0

```typescript
// Bi-Directional
const NumberToString = Type.Codec(Type.Number())
  .Decode(value => value.toString())
  .Encode(value => parseFloat(value))

// Uni-Directional
const NumberToStringDecode = Type.Decode(Type.Number(), value => value.toString())
const NumberToStringEncode = Type.Encode(Type.Number(), (value: number) => value.toString())
```

<a name="Const"></a>

## Type.Const

The Const type has been removed in 1.0. This type was originally used to create structural type representations from constant TypeScript values. 1.0 deprecates this functionality in favor of Script which can parse values into structural representations.

### Fallback

[Const](/example/legacy/const.ts)

### Example

0.34.x

```typescript
const T = Type.Const({ x: 1, y: 2, z: 3 } as const) // const T: TObject<{
                                                    //   TReadonly<TLiteral<1>>
                                                    //   TReadonly<TLiteral<2>>
                                                    //   TReadonly<TLiteral<3>>
                                                    // }>
```

1.0.0

```typescript
const T = Type.Script(`{ x: 1, y: 2, z: 3 }`)       // const T: TObject<{
                                                    //   x: TLiteral<1>;
                                                    //   y: TLiteral<2>;
                                                    //   z: TLiteral<3>;
                                                    // }>

// Optional: If readonly is required.

const S = Type.Script({ T }, `{
  readonly [K in keyof T]: T[K]  
}`)                                                 // const S: TObject<{
                                                    //   x: TReadonly<TLiteral<1>>;
                                                    //   y: TReadonly<TLiteral<2>>;
                                                    //   z: TReadonly<TLiteral<3>>;
                                                    // }>
```

<a name="PickOmit"></a>

## Type.Pick and Type.Omit

Version 1.0 updates Pick and Omit to return evaluated Object types when applied to Union and Intersect types. This change aligns with V1’s ability to evaluate logical type expressions for mapped types. As a consequence, the return structures of Pick and Omit may vary depending on the source type being used.

In 0.34.x, Pick and Omit would simply traverse a logical type expression and select properties from embedded Object types. In 1.0, Pick and Omit evaluate the result into a normalized Object type. Both 0.34.x and 1.0 return semantically equivalent types, but in 1.0 the result is reduced to its simplest form.

### Fallback

[Pick](/example/legacy/pick.ts) | [Omit](/example/legacy/omit.ts)

### Example

0.34.x

```typescript
const X = Type.Object({ x: Type.Number(), z: Type.Number() })
const Y = Type.Object({ y: Type.Number(), z: Type.Literal(1) })
const Z = Type.Intersect([X, Y])

const T = Type.Pick(Z, ['z'])                       // const T: TIntersect<[TObject<{
                                                    //   z: TNumber;
                                                    // }>, TObject<{
                                                    //   z: TLiteral<1>
                                                    // }>]>
```

1.0.0

```typescript
const X = Type.Object({ x: Type.Number(), z: Type.Number() })
const Y = Type.Object({ y: Type.Number(), z: Type.Literal(1) })
const Z = Type.Intersect([X, Y])

const T = Type.Pick(Z, ['z'])                       // const T: Type.TObject<{
                                                    //   z: Type.TLiteral<1>;
                                                    // }>
```


<a name="TypeCompiler"></a>

## TypeCompiler

Version 1.0 makes API changes to the TypeBox compiler but retains the same functionality. The biggest change in 1.0 is the renaming of TypeCheck to Validator. Implementations that reference TypeCheck will need to updated reference Validator. Additionally, the TypeCompiler namespace has been deprecated, implementations can now use the Compile function exported on the submodule.

### Example

0.34.x

```typescript
import { TypeCompiler, TypeCheck } from '@sinclair/typebox/compiler'

const C = TypeCompiler.Compile(Type.String())       // TypeCheck<TString>

C.Check('hello') // true
```

1.0.0

```typescript
import { Compile, Validator } from 'typebox/compile'

const C = Compile(Type.String())                    // Validator<{}, TString>

C.Check('hello') // true
```

<a name="References"></a>

## References

Version 1.0 introduces a model for handling referential types. This model is reflected across Value and Compiler submodules. In 1.0, references are new passed via a optional Context object. This replaces the `references` array in 0.34.x. 

### Example

0.34.x

```typescript
const A = Type.String({ $id: 'A' })
const B = Type.Number({ $id: 'B' })

const T = Type.Object({
  a: Type.Unsafe<Static<typeof A>>(Type.Ref('A')),  // Unsafe Static for Inference
  b: Type.Unsafe<Static<typeof B>>(Type.Ref('B')),
})

const C = TypeCompiler.Compile(T, [A, B])           // References Array

const R = C.Decode({ a: '', b: 1 })                 // const R: { a: string, b: number }
```

1.0.0

```typescript
const A = Type.String()
const B = Type.Number()

const T = Type.Object({
  a: Type.Ref('A'),
  b: Type.Ref('B')
})

const C = Compile({ A, B }, T)                      // const R: { a: string, b: number }
```

<a name="FormatRegistry"></a>

## FormatRegistry

TypeBox 1.0 moves the FormatRegistry to the Format submodule.

### Example

0.34.x

```typescript
import { FormatRegistry } from '@sinclair/typebox'

FormatRegistry.Set('foo', value => value === 'foo')
```

1.0.0

```typescript
import Format from 'typebox/format'

Format.Set('foo', value => value === 'foo')
```

<a name="TypeRegistry"></a>

## TypeRegistry

TypeBox 1.0 removes the TypeRegistry. This registry has been replaced with Type.Unsafe and Type.Refine.

### Example

0.34.x

```typescript
import { TypeRegistry, Kind, TSchema } from '@sinclair/typebox'

// Definition
interface TFoo extends TSchema {
  [Kind]: 'Foo'  
  static: 'Foo'  // Static
}
// Check
TypeRegistry.Set('Foo', (value) => value === 'Foo')

// Factory
function Foo(): TFoo {
  return { [Kind]: 'Foo' } as never
}

```

1.0.0

```typescript
import Type from 'typebox'

export type TFoo = Type.TUnsafe<'Foo'>

export function Foo(): TFoo {
  return Type.Refine(Type.Unsafe<'Foo'>({ type: 'Foo' }), 
    value => value === 'Foo',
    _value => 'Expected Foo')
}
```

<a name="TypeGuard"></a>

## TypeGuard

TypeBox 1.0 removes the TypeGuard. The `Is` functions have been moved to `Type.*`.

### Example

0.34.x

```typescript
import { Type, TypeGuard } from '@sinclair/typebox'

const T = Type.String()

const R = TypeGuard.IsString(T)                     // const R = true
```

1.0.0

```typescript
import Type from 'typebox'

const T = Type.String()

const R = Type.IsString(T)                          // const R = true
```

<a name="Errors"></a>

## Value.Errors

Version 1.0 changes the Errors() return type from Iterator to Array. It also updates the Error to be inline with Ajv. This change enables TypeBox errors to integrate with existing systems that report errors using the Ajv structure. Existing applications will need to update error handling inline with the new structure.

### Error Interface

0.34.x

```typescript
export interface ValueError {
  type: ValueErrorType
  schema: TSchema
  path: string
  value: unknown
  message: string
  errors: ValueErrorIterator[]
}
```

1.0.0

```typescript
interface TLocalizedValidationError {
  keyword: string
  schemaPath: string
  instancePath: string
  params: object
  message: string
}
```

### Example

0.34.x

```typescript
import { Value } from '@sinclair/typebox/value'

const T = Type.Number()

const E = [...Value.Errors(T, 'not a number')]      // IterableIterator<Error>
```

1.0.0

```typescript
import Value from 'typebox/value'

const T = Type.Number()

const E = Value.Errors(T, 'not a number')            // TLocalizedValidationError[]
```

<a name="Cast"></a>

## Value.Cast

Version 1.0 renames Cast to Repair.

### Example

0.34.x

```typescript
const T = Type.Object({ x: Type.Number() })

const R = Value.Cast(T, { })                        // const R = { x: 0 }
```

1.0.0

```typescript
const T = Type.Object({ x: Type.Number() })

const R = Value.Repair(T, { })                        // const R = { x: 0 }
```

<a name="SetErrorFunction"></a>

## SetErrorFunction

TypeBox 1.0 removes the SetErrorFunction callback. This callback was original written to provide internationalization (i18n) hooks for error messages. As Version 1.0 adds built-in support for error message localization, the SetErrorFunction as been removed. Error localization has been moved to the `system` module.

### Example

0.34.x

```typescript
import { SetErrorFunction, DefaultErrorFunction, ValueErrorType } from '@sinclair/typebox/errors'

SetErrorFunction((error) => { // i18n override
  switch(error.errorType) {
    /* en-US */ case ValueErrorType.String: return 'Expected string'
    /* fr-FR */ case ValueErrorType.Number: return 'Nombre attendu'  
    /* ko-KR */ case ValueErrorType.Boolean: return '예상 부울'      
    /* en-US */ default: return DefaultErrorFunction(error)          
  }
})
```

1.0.0

```typescript
import { Locale } from 'typebox/system'

Locale.Set(Locale.en_US)                            // en-US
Locale.Set(Locale.fr_FR)                            // fr-FR
Locale.Set(Locale.ko_KR)                            // ko-KR
Locale.Reset()                                      // en-US
```

<a name="CustomErrors"></a>

## CustomErrors

A common pattern for handling custom errors in 0.34.x was to use the SetErrorFunction to intercept the `errorMessage` property and remap errors when it was present. Since SetErrorFunction has been removed in 1.0, implementations will need to adopt a new strategy for overriding error messages. In 1.0, errors are structured inline with Ajv errors to promote better interoperability with reporting tools that understand Ajv structures, and the mechanisms for handling sub-schema dereferencing have changed. Refer to the provided `custom-errors.ts` fallback as a reference for handling custom error messages in 1.0.

### Fallback

[CustomErrors](/example/legacy/custom-errors.ts)

0.34.x 

```typescript
SetErrorFunction((parameter) =>
  "errorMessage" in parameter.schema
    ? (parameter.schema.errorMessage as string)
    : DefaultErrorFunction(parameter),
)
```

1.0.0

```typescript
import { CustomErrors } from './legacy/custom-errors' // refer to fallback implementation
import Type from 'typebox'

const T = Type.Object({
  x: Type.Number({ errorMessage: 'Expected X Component' }),
  y: Type.Number({ errorMessage: 'Expected Y Component' })
})

const E = CustomErrors(T, { x: '0', y: '0' })       // const E = [{
                                                    //   keyword: 'type',
                                                    //   schemaPath: '#/properties/x',  
                                                    //   instancePath: '/x',
                                                    //   params: { type: "number" },    
                                                    //   message: "Expected X Component"
                                                    // }, {
                                                    //   keyword: "type",
                                                    //   schemaPath: '#/properties/y',  
                                                    //   instancePath: '/y',
                                                    //   params: { type: "number" },    
                                                    //   message: 'Expected Y Component'
                                                    // }]
```