md hello-effect-schema
cd hello-effect-schema
pnpm init
pnpm i typescript @effect/schema effect fast-check vitest
Make tsconfig.json
:
// tsconfig.json
{
"compilerOptions": {
"target": "es2016",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"exactOptionalPropertyTypes": true
},
"include": ["**/*.ts"]
}
Make index.test.ts
:
// index.test.ts
import { test, expect, expectTypeOf } from 'vitest'
import { Schema as S } from '@effect/schema'
This is a schema with two properties: name
is a string, and age
is a number that comes in as a string.
const Person = S.Struct({
name: S.String,
age: S.NumberFromString,
})
Note that Person
kind of looks like a TypeScript type, but it's not - it's a JavaScript object. We can obtain the corresponding type though:
type Person = typeof Person.Type
// equivalent to
// {
// name: string
// age: number
// }
const p = {
name: 'alice',
age: 42,
} satisfies Person
Note
It might seem strange to give the type the same name as the schema object, but it's idiomatic.
One of the things a schema does is convert between some incoming form, to the form we want to work with.
In this example, we said age
is a number that "comes in" as a string: Maybe it's persisted that way, or maybe we get it that way from an HTML input, or from an API call. In this case the encoded form is a string, and the decoded form is a number.
test('decodes Person', () => {
const decode = S.decodeSync(Person)
const encoded = {
name: 'Alice',
age: '25', // <- string
}
const decoded = decode(encoded)
expect(decoded).toEqual({
name: 'Alice',
age: 25, // <- number
})
expectTypeOf(decoded).toMatchTypeOf<Person>()
})