Creating a custom Union Transformation in TypeScript using the Effect library involves a few step...
I’m trying to build a custom Union Transformation. My aim is to convert from and to a custom data type called IndexType. This type represents a pointer to the original type. Any tips or hints you can share would be super helpful!
also typescript complains about MyUnion Schema having the Context as unknown
const IndexType = Schema.Struct({
index: Schema.Number,
});
const MyUnion = <Members extends ReadonlyArray<Schema.Schema.Any>>(
...members: Members
) =>
Schema.transformOrFail(IndexType, Schema.Union(...members), {
strict: true,
encode: (value, toA) => {
const index = members.findIndex((member) => Schema.is(member, value));
return ParseResult.succeed({
index,
});
},
decode: (value) => {
const index = Number(value.index);
if (index < 0 || index >= members.length) {
throw new Error("Invalid index");
}
return ParseResult.decode(members[index])(value);
},
});
const schema = MyUnion(
Schema.Struct({
a: Schema.String,
}),
Schema.Struct({
b: Schema.String,
}),
Schema.Struct({
c: Schema.String,
})
);
const dataA = {
a: "hello",
};
const dataB = {
b: "world",
};
const dataC = {
c: "!",
};
const encoded = Schema.encodeUnknownSync(schema)(dataB);
//should return { index: 1 } , but it returns { index: 0 }
console.log(encoded);
const decoded = Schema.decodeUnknownSync(schema)(encoded);
// should return { b: "world" }, but it fails with an error
// ParseError: ({ readonly index: number } <-> { readonly a: string } | { readonly b: string } | { readonly c: string })
// └─ Transformation process failure
// └─ { readonly a: string }
// └─ ["a"]
// └─ is missingconst IndexType = Schema.Struct({
index: Schema.Number,
});
const MyUnion = <Members extends ReadonlyArray<Schema.Schema.Any>>(
...members: Members
) =>
Schema.transformOrFail(IndexType, Schema.Union(...members), {
strict: true,
encode: (value, toA) => {
const index = members.findIndex((member) => Schema.is(member, value));
return ParseResult.succeed({
index,
});
},
decode: (value) => {
const index = Number(value.index);
if (index < 0 || index >= members.length) {
throw new Error("Invalid index");
}
return ParseResult.decode(members[index])(value);
},
});
const schema = MyUnion(
Schema.Struct({
a: Schema.String,
}),
Schema.Struct({
b: Schema.String,
}),
Schema.Struct({
c: Schema.String,
})
);
const dataA = {
a: "hello",
};
const dataB = {
b: "world",
};
const dataC = {
c: "!",
};
const encoded = Schema.encodeUnknownSync(schema)(dataB);
//should return { index: 1 } , but it returns { index: 0 }
console.log(encoded);
const decoded = Schema.decodeUnknownSync(schema)(encoded);
// should return { b: "world" }, but it fails with an error
// ParseError: ({ readonly index: number } <-> { readonly a: string } | { readonly b: string } | { readonly c: string })
// └─ Transformation process failure
// └─ { readonly a: string }
// └─ ["a"]
// └─ is missingalso typescript complains about MyUnion Schema having the Context as unknown
Types of property 'Context' are incompatible.
Type 'unknown' is not assignable to type 'never'.ts(2345) Types of property 'Context' are incompatible.
Type 'unknown' is not assignable to type 'never'.ts(2345)