fabian-hiller / valibot

The modular and type safe schema library for validating structural data 🤖
https://valibot.dev
MIT License
6.32k stars 204 forks source link

proposal: making the input type of an array schema ReadonlyArray to get flexibility #906

Open m-shaka opened 3 weeks ago

m-shaka commented 3 weeks ago

Even if you define a ReadonlyArray schema, you get a writable array type through InferInput. However, it could be nicer to make it ReadonlyArray.

import * as v from 'valibot';

const Schema = v.pipe(v.array(v.string()), v.readonly());

type Input = v.InferInput<typeof Schema>;
type Output = v.InferOutput<typeof Schema>;
const arr: readonly string[] = [];
const _i: Input = arr; // error
const _o: Output = arr;

playground

My use case is Hono RPC. Hono RPC provides you with type information of the request body using a Valibot schema you define

const res = await client.posts.$post({
  json: {
    tags: ['React', 'TypeScript'],
  },
})

The type of json.tags here is Array, so you can't pass a ReadonlyArray<string> value without type assertion, which is a bit annoying.

I know Array type is more natural, but making it ReadonlyArray is not harmful. Array is a subtype of ReadonlyArray so you can pass Array as well as ReadonlyArray to a place where ReadonlyArray is expected.

fabian-hiller commented 3 weeks ago

Thank you for reaching out! Maybe it is better if Hono wraps the input type in readonly to allow readonly values as input? At the moment readonly is a transformation action and therefore only affects the output of the schema.

m-shaka commented 3 weeks ago

I appreciate your quick response!

Yeah, I understand you think Hono is responsible for it, not Valibot. However, Hono RPC handles tons of types and has a performance issue relating to type calculation. Also, we should transform array types recursively, which is a bit heavy task for the type checker.

So, the point is that my proposal possibly won't break compatibility. ReadonlyArray is not intuitive here, but does not harm anything, I think

fabian-hiller commented 3 weeks ago

is not intuitive here, but does not harm anything, I think

This is theoretically true, but it breaks the philosophy of our pipe method. A transformation can only affect the output, not the input. If someone uses the input type somewhere, it may also break their code if they treat it as mutable. 😐

I am still happy to discuss this.