Given a codec such as the following, I wonder if there would be a generic mechanism by which we could opt into encode behaviour such that undefined properties would be excluded from objects.
import * as t from 'io-ts';
export const MyCodec = t.type({
name: t.string,
});
const implementsMyCodec = {
name: 'name',
propertyNotDefinedInMyCodec: 'value',
};
console.log(MyCodec.encode(implementsMyCodec));
// Output includes the property propertyNotDefinedInMyCodec
When using io-ts as a data-marshalling and validation tool for inputs and outputs, I would like to make sure that I'm not accidentally leaking properties on outputs from my system. It would be great to have io-ts types as the source of truth for this behaviour.
Off-topic: io-ts is a bit of a revelation to me. Keep up the great work!
@ggoodman I'm working on this right now. My plan is to deprecate the type combinator in favour of a xxx (name to be determined) combinator that strips additional properties while decoding / encoding (and making the exact combinator less useful). In particular I'm working on a PR that modifies the internal intersection algorithm in order to support such a combinator.
@gcanti I did also hit the issue with intersection implementation while prototyping own strip combinator: looks like intersection is passing decoded value sequentially to next type, so intersection of 2 stripped types returns wrong result:
const getProps = (type: t.HasProps): t.Props => {
switch (type._tag) {
case "RefinementType":
case "ReadonlyType":
return getProps(type.type)
case "InterfaceType":
case "StrictType":
case "PartialType":
return type.props
case "IntersectionType":
return type.types.reduce<t.Props>((props, type) => Object.assign(props, getProps(type)), {})
}
}
export function strip<RT extends t.HasProps>(type: RT): t.Type<t.TypeOf<RT>, t.OutputOf<RT>, t.InputOf<RT>> {
const props: t.Props = getProps(type)
const keys = Object.keys(props)
const len = keys.length
return new t.Type(
type.name,
t.exact(type).is,
(m, c) => type.validate(m, c).map((o: any) => {
const r: any = {}
for (let i = 0; i < len; i++) {
const k = keys[i]
if (Object.prototype.hasOwnProperty.call(o, k)) {
r[k] = o[k]
}
}
return r
}),
type.encode
)
}
type UserProfile = {
readonly name: string
readonly title?: string
}
const UserProfile: t.Type<UserProfile> = t.intersection([
strip(t.interface({
name: t.string
})),
strip(t.partial({
title: t.string
}))
])
const result = UserProfile.decode({ name: "John", title: "Programmer" })
Resulting value will be an empty object.
@lostintime running your snippet on the intersection branch returns the expected result
console.log(UserProfile.decode({ name: 'John', title: 'Programmer', a: 1 }))
/*
right({
"name": "John",
"title": "Programmer"
})
*/
console.log(UserProfile.decode({ name: 'John', a: 1 }))
/*
right({
"name": "John"
})
*/
deprecate the
typecombinator in favour of a xxx (name to be determined) combinator that strips additional properties while decoding / encoding (and making theexactcombinator less useful)
An even better idea: the very goal of exact is
not accidentally leaking properties on outputs (and input - ed.) from my system
so my plan is
never usage) in tuple and exact, i.e. tuple and exact should strip additional components/properties instead of error out while decoding, and strip additional components/properties while encodingstrict(props) as an alias for exact(type(props)) instead of adding a new strip combinatorClosed this in https://github.com/gcanti/io-ts/pull/277
Hi!
I am having some problems to get the strict be.... strict! 馃槃 What I am trying to achieve is declare an interface that does not allow unknown properties. I thought that strict would do it, but it instead silently removes the unknown properties.
I would like that this
{
includes: [],
unknownProperty: true,
}
Does _not_ pass the validation of this
t.exact(
t.interface({
includes: t.array(t.string),
})
)
I'm currently using decode for same purpose, but a strict encode would be very useful, as it may not fail
Most helpful comment
@ggoodman I'm working on this right now. My plan is to deprecate the
typecombinator in favour of axxx(name to be determined) combinator that strips additional properties while decoding / encoding (and making theexactcombinator less useful). In particular I'm working on a PR that modifies the internalintersectionalgorithm in order to support such a combinator.