fabian-hiller / valibot

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

set() expects Set #685

Closed dearlordylord closed 1 week ago

dearlordylord commented 1 week ago

This is somewhat counterintuitive approach. What parsers usually receive is JSONs over a network that has fewer data types available. For instance, for a Set structure, it'll be an array of unique values over the network. The parser is expected to validate uniqueness and convert to a JS set. Compare with https://valibot.dev/api/isoDate/ : it doesn't expect a JS Date object, after all.

import * as v from 'valibot';

// comes from the api call:
const input = JSON.parse(JSON.stringify({
  uniq: ['a', 'b', 'c']
}));

const Schema = v.object({
  uniq: v.set(v.string())
})

const result = v.safeParse(Schema, input);

// Invalid type: Expected Set but received Array
console.log(result);
fabian-hiller commented 1 week ago

If you expect an array from your JSON, you should also use the array schema. You can then use transform to decode it back to a set.

import * as v from 'valibot';

const Schema = v.object({
  uniq: v.pipe(
    v.array(v.string()),
    v.transform((input) => new Set(input))
  ),
});
dearlordylord commented 1 week ago

thanks for clarification @fabian-hiller ,

for anyone stumbling upon this, the Set behaviour that I expect can be generically represented like this

const set = <S extends BaseSchema<unknown, unknown, BaseIssue<unknown>>>(schema: S) => pipe(
  array(schema),
  check((v) => new Set(v).size === v.length, 'Expected unique items'),
  transform((v) => new Set(v))
);