15 comments

  • throwaw12 3 minutes ago
    I personally love the idea and concept, but struggle to apply to real projects.

    Suppose I have a User with some attributes like birthday, email and whether they have been verified.

    in common codebase, you can see `if (user.verified_at != null)` or something along the lines, in case of parsed code I do feel like I should have types for each of them (or interfaces):

        - UserWithBirthday
        - VerifiedUser, UnverifiedUser
        - UserWithEmail, UserWithoutEmail
    
    (and imagine having a method which accepts user with birthday and email to send an email day before their birthday, would you create UserWithBirthdayAndEmail type?)

    it feels like it is going to bloat the interface space, how do you tackle this problem?

  • Altern4tiveAcc 15 minutes ago
    Zod 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 impact on hot and cold paths. Same for all the allocations caused by custom Option<T>/Result<T,E> implementations.

    I think using Zod at the edge (with branded types and whatnot), while keeping return types as T/Promise<T> to keep a sane relationship with the ecosystem is a good middle ground.

  • exceptione 4 minutes ago
    It is nice the author mentioned F#, because if you want to target the browser (or any JavaScript runtime), you can do from F# directly from fable (https://fable.io). This allows you to program by default in a type safe manner without having to play tricks to circumvent the limits of structural typing.
  • rzmmm 10 minutes ago
    Is there benefit of using this branded type over just encapsulating the raw string in a private variable in closure or class? This feels a bit like forced nominal typing. The Email type doesn't have to be a string, it can be encapsulated so that invalid Emails are not representable.
    • iainmerrick 2 minutes ago
      The main advantage of branding is that it’s a zero-cost abstraction -- the boilerplate vanishes at runtime. Just using a string instead of a containing object can give you a lighter-weight runtime.
  • somat 7 minutes ago
    "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?

    • camdenreslink 1 minute ago
      In some languages you can create a type that is equivalent to a string, but it’s own distinct type (sometimes called the New Type pattern). Which I guess is the same as a struct with a single field, but languages have syntactic sugar, and depending on implementation doesn’t allocate another extra wrapper object on the heap (this would happen in JavaScript/TypeScript).
    • LelouBil 3 minutes ago
      [delayed]
  • lumpysnake 34 minutes ago
    We should make authors disclose how much AI was used to write an article. This reeks of Opus 4.8.
    • lijok 24 minutes ago
      Why should they disclose how much AI was used to write an article?
      • Bjartr 13 minutes ago
        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?

        • lijok 7 minutes ago
          Should they disclose the use of a spellchecker? A translation app? Gramarly? A writing tutor?
          • btrettel 1 minute ago
            A spell checker, grammar checker, and tutor change a relatively small fraction of the writing, preserve the writer's style/voice, and rarely introduce errors that are hard to detect like hallucinations.

            A translation app changes nearly 100% of the content, often changes the writer's style/voice, and can introduce hard to detect errors. But there's a far closer correspondence to what was written by the original writer. The basic ideas are still from the writer. A translation app is not expanding a short idea into something longer, and including some things the original writer never thought in the process.

  • robertlagrant 1 hour ago
    This feels right, and I also have never done it (or had the guts to get others to do it).

    The reason I've not is - say there's an optional field. Currently we call that null, probably, and check each time if it's there or not. I could instead make a type, like User and UserWithPhoneNumber. Should we be making types for each combination of present/absent fields? That can't be right.

    The classic answer is to move the logic inside the domain object, or have a helper function outside the object, so you aren't constantly checking for field presence/absence, but are instead writing the logic once and calling some code.

    I'm not sure in practice types can help with this. But I'd love to be proven wrong.

    • xx_ns 1 hour ago
      I think this is a slightly different problem. The absence of an optional field, if that's a legal state, is meaningful every time you use the type, so you encode it on the field: `phone: ValidPhoneNumber | null`. When it's not null you're still guaranteed a valid phone number. When it is null, that's a legal state you have to handle and which is domain logic, not validation you forgot to do.

      The combinatorial explosion you're picturing only shows up if you make a separate type per combination of present fields, but you don't need to. An independent optional field stays one `T | null`. You only reach for distinct types when fields are correlated and present together because they represent a state, and then it's a discriminated union on a status field, which is N states, not 2^N.

    • frogulis 25 minutes ago
      This explosion of optionality types is (the most important) topic of Rich Hickey's "Maybe Not" talk. I recommend it!

      The short version is: the shape of a type is inherent to the type itself, but the optionality of its members is dependent on the situation. A type system that solves this problem separates these concepts to allow for this distinction.

      I _suspect_ it's possible to implement something like that in typescript but I haven't tried it myself (and I doubt it's very ergonomic).

    • pillmillipedes 1 hour ago
      if a user with/without phone number are equally valid states to be then types won't help you much. I think it's more about writing

        class User{phone: ?PhoneNumber}
      
      over

        class User{phone: ?string}.
      • throwwwll 40 minutes ago
        To expand and give some notion of good taste:

        It's more about writing

            struct User {phone: MaybePhoneNumber} // give or take, it's a monoid
        
        over

            struct User {phone: Option<String>}
  • hankbond 48 minutes ago
    As a new TypeScript user these are concepts that have greatly helped me simplify my code and improve reliability discrete of testing. Many LLMs guide in this direction if you loosely ask them, but having a concise post like this with the what and the why is fantastic as reference material. The suggestion to use Separation and a Linter rule is something I'm going to immediately look into for my current project. Great post!
  • ivolimmen 28 minutes ago
    One of the pillars of Domain Driven Design. I love working on a pure DDD application but I do not often convince my team (I am a constant) that this is the best way ...
    • jve 15 minutes ago
      > I am a constant

      What did you mean by that? You don't accept mutability or any inputs on your state of mind?

  • ramses0 34 minutes ago
    Meta: in addition to upvotes and downvotes, we almost need a slop/not-slop slider.

    This one barely scrapes by at what feels like 30-40% "slop": "honestly", "the one thing", etc...

    ...but I did learn something about "Brand" types, and have personally tried to do more of "parse don't validate" in my own code.

    Recently I did this similar trick for `exec( ValidExecutable(...) )` [python], where it required tagging/washing through a private function/variable to "get" the private bit.

    All the scanners tend to light up when they see "exec" at all (eg: `exec( "pandoc" )` for PDF generation), but I needed to hard code a few "expected" pandoc locations so the imaginary hackers couldn't shadow "pandoc" on a path location they controlled.

  • conartist6 1 hour ago
    Don't forget to freeze the objects
  • srobbani 20 minutes ago
    Bro, this is cool! I will take over your ide in my project! aicompiler.dev
  • yahavthehackern 28 minutes ago
    [dead]
  • ShizuhaLabs 1 hour ago
    [flagged]