今天跟大家介紹如何組合、重用 @effect/schema
。
要描述一個 Product type ,我們可以使用 S.struct
,例如下面這樣
import * as S from '@effect/schema/Schema'
const adminSchema = S.struct({
_tag: S.literal('Administrator'),
name: S.string,
})
/*
{
_tag: 'Administrator',
name: string
}
*/
struct 的每個 key 後面可以是任意一種 shema
const nameSchema = S.struct({
first: S.string,
last: S.string,
})
const adminSchema = S.struct({
_tag: S.literal('Administrator'),
name: nameSchema
})
/*
{
_tag: 'Administrator',
name: {
fitst: string,
last: string
}
}
*/
用起來就像 js 的 Record
一樣,非常直覺
有 Record
當然也就會有 Array
和 Tuple
const usersSchema = S.array(userSchema) // User []
const couple = S.tuple(userSchema, userSchema) // [User, User]
有時候我們只是想在別的已經定義好的型別的基礎上,做一些小改變,而不想要重新新增一個相似度非常高的型別的時候,以上三個工具就非常的好用。
const nameSchema = S.struct({
first: S.string,
last: S.string,
})
/*
{
fitst: string,
last: string
}
*/
const newNameSchema = pipe(
nameSchema,
S.extend(S.struct({
middle: S.string
}))
)
/*
{
first: string,
middle: string,
last: string
}
*/
const firstNameSchema = pipe(
nameSchema,
S.pick('first')
)
/*
{
fitst: string,
}
*/
const lastNameSchema = pipe(
nameSchema,
S.omit('first')
)
/*
{
last: string,
}
*/
const adminSchema = S.struct({
_tag: S.literal('Administrator'),
name: S.string,
})
const memberSchema = S.struct({
_tag: S.literal('Member'),
name: S.string,
})
const user = S.union(adminSchema, memberSchema)
/*
{
_tag: "Administrator",
name: string
} | {
_tag: "Member",
name: string
}
*/
其實定義 schema 的過程很像是定義型別。要是需要使用型別的時候,也要重複再寫一次類似的結構,就顯得有些麻煩了。幸運的是 @effect/schema
提供了我們轉換的工具。
const userSchema = S.struct({
name: S.string,
birth: S.Date,
})
type UserFrom = S.Schema.From<typeof userSchema>
/*
{
name: string,
birth: string
}
*/
type UserTo = S.Schema.From<typeof userSchema>
/*
{
name: string,
birth: Date
}
*/
我們在 D06 - 測試驅動開發曾經提到過藉由 Data.Case
的擴展,我們能比對兩個物件是否相等,並且自動產生型別。
Data.Case
可以讓原本不支援物件比對的 JS 物件,變得可以比對import { Equal } from 'effect' const result = Equal.equals(textInput1)(textInput)
更重要的是可以幫你產生 constructor
const ofValid = Data.tagged<ValidTextInput>('ValidTextInput') const courseName1 = ofValid({ value: 'HTML/CSS/JS' })
可是如果使用上面的方式,解析出來的型別,是無法具有 Data.Case
性質的。
沒有 Data.case
,我們就無法進行 Equal
的比對,也沒辦法有自動生成的 constructor,真的很可惜,所以明天我們會介紹如何使用 @effect/schema
的 Class
來自動幫我們完成以下這些事情。