Type safety
at runtime
in typescript
@kajetansw
kajetan.dev
Kajetan Świątek
👨🎨 Front-end developer
🇵🇱 Wrocław
typescript
is not perfect
(not every tool will meet all expectations of all users)
runtime type system:
The missing piece?
underneath, typescript is
plain javascript
No interfaces
and type aliases
No runtime validation
after compilation
interface Hero {
name: string;
gender: string;
}
const url = 'https://swapi.dev/api/people/1';
const hero: Hero =
await fetch(url).then(r => r.json());
// How sure are we that the returned object is
// really of type `Hero`?
type assertion of runtime values
what's
the solution?
(Runtime validators, schema validators, json decoders)
Runtime types
elm
what abouT ?
what abouT ?
benchmarks (OPS/sec)
typescript-runtime-type-benchmarks
what abouT ?
jquense/yup
⭐️ 16,787
ajv-validator/ajv
⭐️ 10,921
colinhacks/zod
⭐️ 7,118
gcanti/io-ts
⭐️ 5,366
pelotom/runtypes
⭐️ 2,074
library by github stars
PREVIEW
zod
zod - schema primitives
import { z } from "zod";
// primitive values
z.string();
z.number();
z.bigint();
z.boolean();
z.date();
// empty types
z.undefined();
z.null();
zod - being more specific
// strings
z.string().max(5);
z.string().min(5);
z.string().length(5);
z.string().email();
z.string().url();
// etc.
// numbers
z.number().gt(5);
z.number().gte(5);
z.number().lt(5);
z.number().lte(5);
z.number().int();
// etc.
zod - complex data
const Dog = z.object({
name: z.string(),
age: z.number(),
});
// extract the inferred type
type Dog = z.infer<typeof Dog>;
// equivalent to:
type Dog = {
name: string;
age: number;
};
Also combinators for
- extending
- merging
- picking
- omitting
zod - usage
// creating a schema for strings
const mySchema = z.string();
// parsing
mySchema.parse("tuna"); // "tuna"
mySchema.parse(12); // throws ZodError
// doesn't throw error if validation fails
mySchema.safeParse("tuna");
// { success: true; data: "tuna" }
mySchema.safeParse(12);
// { success: false; error: ZodError }
io-ts (from fp-ts ecosystem)
import * as t from 'io-ts'
// Primitives
t.string
t.number
// Combinators
const User = t.type({
userId: t.number,
name: t.string
})
type User = t.TypeOf<typeof User>
import * as t from 'io-ts'
// Decoding
t.string.decode(/*...*/)
// returns Either<E, A>
type Either<E, A> =
| {
readonly _tag: 'Left'
readonly left: E
}
| {
readonly _tag: 'Right'
readonly right: A
}
your turn!
TRY THEM OUT!
Thank you!
✋😎
@kajetansw
kajetan.dev
typescript-runtime-type-benchmarks
Type safety at runtime v2
By Kajetan Świątek
Type safety at runtime v2
- 290