Create ArkType type from standard schema from other library.

Is it possible for me to integrate Standard Schemas from other libraries such as Effect.Schema or Zod with ArkType? I am using Effect and trying to use their Config module which seems built on their Schema type which can be exported to Standard Schema. I really don't want to redefine my schemas/types and am wondering if ArkType supports using other Standard Schema types to create its types?
7 Replies
ssalbdivad
ssalbdivad3w ago
I actually love this idea that any standard schema would just be a valid arktype definition I don't know why I haven't already done it I will add that in the next release (of course you can do it manually now with a thin wrapper like typeFromStandardSchema but there's really no reason to not have that concept built-in) so you could use any standard-schema compliant object anywhere it would be valid to pass a Type
Damian Reeves
Damian ReevesOP3w ago
That would be so awesome. How would one go about implementing typeFromStandardSchema in the interim? Is it actually really simple?
ssalbdivad
ssalbdivad3w ago
yeah it is one sec @Damian Reeves try this:
import type { StandardSchemaV1 } from "@standard-schema/spec"
import { type, type Out } from "arktype"
import z from "zod"

type standardSchemaToArkType<
schema extends StandardSchemaV1,
i = StandardSchemaV1.InferInput<schema>,
o = StandardSchemaV1.InferOutput<schema>
> = [i, o] extends [o, i] ? type<i> : type<(In: i) => Out<o>>

const typeFromStandardSchema = <schema extends StandardSchemaV1>(
schema: schema
): standardSchemaToArkType<schema> =>
type.unknown.pipe((v, ctx) => {
const result = schema["~standard"].validate(
v
) as StandardSchemaV1.Result<unknown>

if (result.issues) {
for (const { message, path } of result.issues) {
if (path) {
ctx.error({
message: message,
path: path.map(k => (typeof k === "object" ? k.key : k))
})
} else {
ctx.error({
message
})
}
}
} else {
return result.value
}
}) as never

const TFromZod = typeFromStandardSchema(
z.object({
foo: z.string()
})
)

const valid = TFromZod({ foo: "foo" })
const invalid = TFromZod({ foo: 5 })
import type { StandardSchemaV1 } from "@standard-schema/spec"
import { type, type Out } from "arktype"
import z from "zod"

type standardSchemaToArkType<
schema extends StandardSchemaV1,
i = StandardSchemaV1.InferInput<schema>,
o = StandardSchemaV1.InferOutput<schema>
> = [i, o] extends [o, i] ? type<i> : type<(In: i) => Out<o>>

const typeFromStandardSchema = <schema extends StandardSchemaV1>(
schema: schema
): standardSchemaToArkType<schema> =>
type.unknown.pipe((v, ctx) => {
const result = schema["~standard"].validate(
v
) as StandardSchemaV1.Result<unknown>

if (result.issues) {
for (const { message, path } of result.issues) {
if (path) {
ctx.error({
message: message,
path: path.map(k => (typeof k === "object" ? k.key : k))
})
} else {
ctx.error({
message
})
}
}
} else {
return result.value
}
}) as never

const TFromZod = typeFromStandardSchema(
z.object({
foo: z.string()
})
)

const valid = TFromZod({ foo: "foo" })
const invalid = TFromZod({ foo: 5 })
there was a little more than I was originally imagining because of the error mapping but still pretty easy and seems to work
Damian Reeves
Damian ReevesOP3w ago
Thanks so much! I'll take a look and give it a shot
ssalbdivad
ssalbdivad4d ago
thanks for the great idea! @Damian Reeves as of 2.1.28 you can pass Standard Schema directly to ArkType:
import { type } from "arktype"
import * as v from "valibot"
import z from "zod"

const ZodAddress = z.object({
street: z.string(),
city: z.string()
})

const User = type({
name: "string",
age: v.number(),
address: ZodAddress
})
import { type } from "arktype"
import * as v from "valibot"
import z from "zod"

const ZodAddress = z.object({
street: z.string(),
city: z.string()
})

const User = type({
name: "string",
age: v.number(),
address: ZodAddress
})
log(n)
log(n)3d ago
"Migrate your codebase to ArkType" and it's all type(z.object({ ... }))

Did you find this page helpful?