sinclairzx81 / typebox

Json Schema Type Builder with Static Type Resolution for TypeScript
Other
4.79k stars 152 forks source link

Not entirely obvious which type to use... #427

Closed russell-dot-js closed 1 year ago

russell-dot-js commented 1 year ago

Imagine you wanted to write this function:

function isA<T>(value: unknown, schema: Schema<T>): value is T {
  return Value.Check(schema, value);
}

Schema itself is not generic, but I have to imagine there's a type somewhere in the library that represents "schema for T". I can't for the life of me find it anywhere.

sinclairzx81 commented 1 year ago

@russell-dot-js Hi,

TypeBox doesn't implement Schema<T> or schema for T functionality as static types are erased by the TS compiler on compilation. As the types are erased, there's no way convert the static type into a runtime schema (as runtime information about the static type is lost). To get around this limitation, TypeScript instead requires one to explicitly define the runtime type, then map that back to the static type (This is the approach used by TypeBox, as well as libraries like Zod, Io-Ts)

Updated Code Example

The code above can be loosely expressed as the following, however you will need to pass valid types of TSchema.

TypeScript Link Here

import { Type, Static, TSchema } from '@sinclair/typebox'
import { Value } from '@sinclair/typebox/value'

function isA<T extends TSchema>(value: unknown, schema: T): value is Static<T> {
  return Value.Check(schema, value)
}

const result = isA('foo', Type.String()) // true
            // ^
            // isA<TString>(value: unknown, schema: TString): value is string <- infer 

Alternative Solutions

If you need Schema<T> like functionality, there are a few solution that exist, but they require plugins to the TypeScript compiler (and perform compile time transformations). Checkout the typia project which largely does this.

For TypeBox, you can try https://sinclairzx81.github.io/typebox-workbench/ which is a small tool that may be able to help transform your types into TB types (making them compatible with the function above)

Hope this helps S

sinclairzx81 commented 1 year ago

@russell-dot-js Going to close off this one as there's no way to produce a Schema<T> for TS types at runtime. But have a review of either the workbench link (which can convert TS types into TB types) or projects like typia which use compiler transforms to emit validation code. Both options use the TS compiler API to obtain runtime information for a type, but this functionality is not possible when using Typescript alone.

Cheers S