Leveraging the type system to avoid mistakes
Types can definitely help with data well-formedness but personally I'm very suspicious of 'mini-types' like Name and CartID. If the data you're wrapping has no internal structure (that can be formally verified) and you're just using the type system as an argument checker then it's not clear to me that you're really adding much value. If CartID and ProductID are both just strings what's to stop a user from doing the same as:  CartID cartId = new CartID(productId.toString());
  addToCart(..., cartId, ...); <-- but look that's really a ProductID!

I'd suggest that while you may have reduced the likelihood of certain errors you have not actually eliminated those errors.The right approach here is to be very suspicious of any methods in your domain that just take a bunch of IDs. Either:(a) Force the caller to resolve the IDs to actual entities before invoking the method:  addToCart(Cart c, Product p, ...)

or (b) Represent the method parameters as a Parameters object or, preferrably, an Event object.  handle(ProductAddedEvent event);

The real problem here is not the type system but a domain that is not sufficiently protected by an Anti-Corruption Layer [1]. Unfortunately most developers are not familiar with this kind of strategic design and languages are not much help here. It would be interesting if there was a language that could flag things like weak ACLs.[1] https://docs.microsoft.com/en-us/azure/architecture/patterns...