Earlier quoted context omitted.
If nothing else, it should be done as a courtesy to those who would like to avoid such content. If the result is better for having used AI, why wouldn't an author want to disclose it?
Should they disclose the use of a spellchecker? A translation app? Gramarly? A writing tutor?
Parse, Don't Validate – In a Language That Doesn't Want You To
51–60 of 107 posts
Re: Parse, Don't Validate – In a Language That Doesn't Want You To
#52Re: Parse, Don't Validate – In a Language That Doesn't Want You To
#53The author found out about the square holes in round peg situation with TS. Functions can implicitly error, and there's no annotation that's enforced to tell you that it might error. FP solves this with Result/Option, but this doesn't fit in TS. Effect is there to find a solution but will fail. Zod is the acceptable middleground in my opinion. Zod will allow you to throw a schema against an object and it'll tell you…
Re: Parse, Don't Validate – In a Language That Doesn't Want You To
#54"TypeScript is structurally typed, which means two types with the same shape are the same type. string is string is string" I don't speak typescript so am probably missing something obvious. but. why would you parse an email(or anything really) into a string? (or string equivalent) When parsed it will end up as a specific email object, that is, something closer to a C struct. What is the articles dance doing?
Javascript doesn't have structs. The idea is that you have data on one hand and you have type witness about that data on the other hand. Type witness is something for the type system. But here you encounter the limits of structural typing versus nominal typing, because structural typing isn't able to witness that directly. In sufficiently strong nominal type systems, I can hide the constructor for an EmailAddress typ…
If I parsed an emailAddress the thing that came out it would look like {'domain':'example.com', 'user':'john-doe'} or emailaddr.domain emailaddr.user and a emailaddr.address method if you like that form. Even if what I parsed ended up as a single string-like field, I would still name that field. emailaddr.address
Salutes for the bit on hiding the constructor, that makes a lot of sense.
It probably does not help anything that in my one attempt at making a javascript web application I did not bother trying to understand how javascript likes it's objects and just forced a python looking model onto it. If any of the web development team saw my code I would definitely get laughed out of the club.
Re: Parse, Don't Validate – In a Language That Doesn't Want You To
#55So I just define my types and then use typescript-json-schema or similar to build a JSON Schema at build time (i.e. from an npm script) which then I use to validate input using ajv.
The only thing I do on top of that is to use annotations like "@minimum 0" (or, in the email example, "@format email") where the base types are not enough, but those simply go inside comments.
So the compiled package only has ajv as runtime dependency (which you're likely to have anyway, as it's everywhere), you're just defining regular types with some annotations on top and use a dev dependency to build you the JSON Schema. And as popular as zod is, I think JSON Schema is more of a standard and likely to stay with us longer.
I also reference those generated JSON Schemas from my OpenAPI definition, as a bonus.
Re: Parse, Don't Validate – In a Language That Doesn't Want You To
#56Zod is by far the most ergonomic way to express those ideas in TypeScript these days. I miss it when writing code in other languages. The friction with the rest of the ecosystem is real, though. Most code out there expects you to handle errors with exceptions. I get the impression that polymorphic return types could get in the way of JSC/V8/SpiderMonkey's JIT, but I haven't measured it and I'm not sure of the actual…
You can use Pydantic in Python and serde_derive in Rust. I assume most languages have a thing like that.
Re: Parse, Don't Validate – In a Language That Doesn't Want You To
#57Earlier quoted context omitted.
It's pretty trivial to create derived and augmented types with Pick, Omit, Required, Partial. Combined with a few parsing functions that return an object typed to whatever specification you need and you are set IE: type User = { name: string; verified: boolean; email?: string; lastName: string; birthday?: string | { year: string; month: string; date: string; }} type Birthday = Required >; type UserWithBirthday = User…
creation is not a problem, maintenance is. Suppose you want to add one more property to VerifiedUserWithBirthday and UnverifiedUserWithBirthday, you might get 2 more new types, and somewhere at the higher layer call chains you need to know which enclosing type you should pass so that some method in the bottom chain will accept it. I am sure there are more elegant ways, but I am struggling to generalize it to most ent…
If you have VerifiedUserWithBirthday, any value that fails the parsing function is implicitly UnverifiedUserOrUserWithoutBirthday... No need to define it separately. You get the inverse type for free IE a value that is of type User and not of type VerifiedUserWithBirthday.
A new property doesn't mean a new derived type. Only if that new property impacts what a VerifiedUserWithBirthday should represent should the VerifiedUserWithBirthday type be updated and even then, it's not a new type, just an update to an existing type. Again minimal updates needed.
The compiler handles all the validation and will tell you exactly where there are any issues - the compiler is what makes the maintenance cost quite low.
Re: Parse, Don't Validate – In a Language That Doesn't Want You To
#58Earlier quoted context omitted.
The computer-science answer to this problem are called "refinement types", where you can attach arbitrary predicates to a type, e.g. (pseudo-code): fn send_birthday_mail(user: {u: User, u.birthday != null}) Contracts are a similar solution that restricts the predicates to only appearing in function types. The difference between this and an assert is that it gets checked at compile time (it can get quite expensive to…
this looks cool, but you are doing validation when accepting the object, you probably can't do it excessively, for example, if you are dealing with objects with heights, you might have a HumanLikeHeight where height range is between 40cm and 250cm, and you want to send email to that human, would you keep adding these conditions to the predicates?
But you hit performance and/or outright computational limits (halting problem) rather quickly.
Re: Parse, Don't Validate – In a Language That Doesn't Want You To
#59 default: {
const _exhaustive: never = result;
return _exhaustive;
}
...is not how people should implement an exhaustiveness check ever! An exhaustiveness check exhausts your knowledge about the world, it should throw an exception at runtime. Just returning the non-matched case is a recipe for disaster. Do this instead: default:
((value: never) => { throw new Error(`Missing case for value: ${value}`); })(result);Re: Parse, Don't Validate – In a Language That Doesn't Want You To
#60Earlier quoted context omitted.
Javascript doesn't have structs. The idea is that you have data on one hand and you have type witness about that data on the other hand. Type witness is something for the type system. But here you encounter the limits of structural typing versus nominal typing, because structural typing isn't able to witness that directly. In sufficiently strong nominal type systems, I can hide the constructor for an EmailAddress typ…
Javascript does have structs, it calls them objects. If I parsed an emailAddress the thing that came out it would look like {'domain':'example.com', 'user':'john-doe'} or emailaddr.domain emailaddr.user and a emailaddr.address method if you like that form. Even if what I parsed ended up as a single string-like field, I would still name that field. emailaddr.address Salutes for the bit on hiding the constructor, that…