Schema.asSchema
任意のSchema (effect)をSchema<Type, Encoded, Requirements>に変換する
https://effect.website/docs/schema/basic-usage/#asschema
使い所がわからん
Claude Code.icon
「具体的なスキーマ型」を「汎用的な Schema<A, I, R> 型」へ型レベルで広げる(widen する)ためのヘルパー関数です。ランタイムでは何もせず、純粋に TypeScript の型の話だけを解決します。
Schema には「具体型」と「汎用型」の2レイヤーがある
具体型と言ってるのは
Schema.Hoge<..>という形の型のこと
e.g. Schema.Array$<...>, Schema.Union<...>, Schema.Literal<...>, ..
具体型は、フィールド構成・リテラルの中身・タプルの要素などの構造情報を型に保持しています。これは内部のイントロスペクション(JSON Schema 生成、pick/omit、fields へのアクセスなど)のために重要です。
汎用型と言ってるのは
Schema<..>という形の型のこと
Schema<Type, Encoded, Requirements>のこと
table:_
具体型(例: Schema.Struct<...>) 汎用型(Schema<A, I, R>)
構造情報 保持する(fields 等が使える) 失われる
読みやすさ ネストして読みにくい A/I/R に解決され読みやすい
汎用関数への適合 ブレることがある 安定
asSchema がやること
具体型を、この汎用 Schema<A, I, R> に「正規化」します
。「具体型の便利機能はもう要らない、ただの Schema<A, I, R> として扱いたい」というときに使います。
シグネチャはおおよそ次のとおりです:
code:ts
declare const asSchema: <S extends Schema.Schema.All>(
schema: S,
) => Schema.Schema<Schema.Schema.Type<S>, Schema.Schema.Encoded<S>, Schema.Schema.Context<S>>
実装は実質恒等関数で、ランタイムでは受け取ったスキーマをそのまま返すだけです(return schema as any 相当)。違いは戻り値の型表示だけです。
code:ts
const Person = Schema.Struct({
name: Schema.String,
age: Schema.Number,
})
// ^? Schema.Struct<{...}> ← 具体型
const PersonSchema = Schema.asSchema(Person)
// ^? Schema<{ readonly name: string; readonly age: number }, {...}, never> ← 汎用型に展開される
どういうときに使うのか
2. ジェネリックな関数に渡すときの型の一致
「任意のスキーマを受け取る」関数を書くとき、汎用 Schema<A, I, R> を期待するシグネチャに具体型を渡すと、推論がうまくいかなかったり型が合わなかったりすることがあります。asSchema で正規化すると噛み合います。
code:ts
// 「どんなスキーマでも受け取って Type を取り出す」ような関数
function useSchema<A, I, R>(schema: Schema.Schema<A, I, R>) {
// ...
}
// 具体型のまま渡すと推論がブレることがある →
useSchema(Schema.asSchema(Person)) // 汎用型に揃えてから渡すと安定する
3. ライブラリ/共通レイヤーの境界で型を固定する
公開する API の戻り値や、内部実装の詳細(どのコンビネータで作ったか)を呼び出し側に漏らしたくないときに、asSchema で「ただの Schema<A, I, R>」として型を固定できます。具体型を晒すと、実装をリファクタした際に外向きの型が変わってしまいますが、asSchema で蓋をしておけば安定します。