Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: struct.extend and struct.exact #2

Open
MKRhere opened this issue Apr 18, 2020 · 0 comments
Open

Proposal: struct.extend and struct.exact #2

MKRhere opened this issue Apr 18, 2020 · 0 comments
Labels
enhancement New feature or request
Projects

Comments

@MKRhere
Copy link
Member

MKRhere commented Apr 18, 2020

This proposal is two-part because the use of extend ties in with the use of exact. We will see why below.

*1) struct.exact

At the moment, struct only validates loose objects; when there are more props than required, they're simply ignored. This is probably safe for most use-cases, but some times you might want a strict mode where additional props are disallowed.

The proposed API for this is: struct(S).exact(x) -> x is exact S

There will be no change in the type guard. At compile time, exact is similar to loose validation, because any x will always be accepted as input, and it's unsafe to use un-validated props either way. It's only a runtime change where exact fails if there were more props than expected.

Example

const Message = struct({ from: string, to: string, content: string });

const x = { from, to, content };

if (Message.exact(x)) {
  // x is valid
}

const y = { from, to, content, isForward };

if (Message.exact(y)) {
  // y is not valid Message, since it has an unexpected prop `isForward`
}

*2) struct.extend

Currently, extend is its own Higher Order Predicate. Its behaviour is such that it accepts a struct predicate as first param, and a struct as second param. The definition of the first struct is enforced at compile-time; you cannot extend from an arbitrary type (use and for that). x must satisfy both structs, while the second struct may not contradict the first; only extend it.

Problem

Because struct.exact as defined previously is also a predicate, extend will have to disallow exact structs as a parameter, because its runtime validation will fail before being extensible.

Because extend is very tied in to struct, moving it to a method makes extend and exact mutually exclusive. I'd also expect extend to be used as an extension of a previously defined struct, rather than inline definition like extend(struct(...), ...). Making it a method makes a lot of sense.

Example

Existing:

const Message = struct({ from: string, to: string, content: string });

// .. elsewhere

const ForwardedMessage = extend(Message, { isForward: true });

Proposed:

const ForwardedMessage = Message.extend({ isForward: bool });

Unaddressed issues

There are still some concerns to be worried about, namely deeply strict structs, like this one:

const MessageContent = struct({
	type: oneOf("html", "markdown"),
	value: string
}).exact; // notice that MessageContent has been exact-ed

const Message = struct({
	from: string,
	to: string,
	content: MessageContent,
});

Say Message is extended like so:

const MessageWithAttachment = Message.extend({
	content: {
		attachment: string,
	},
});

This check fails to behave as expected at runtime because MessageWithAttachment will always fail as the original struct's content is exacted. This could be solved by having a way to extract the non-exact predicate out of an exact predicate, but we're yet to decide whether implicitly un-exacting structs when extending them is the right way to go.

@MKRhere MKRhere created this issue from a note in Roadmap (To do) Apr 18, 2020
@MKRhere MKRhere added the enhancement New feature or request label Apr 18, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Roadmap
  
To do
Development

No branches or pull requests

1 participant