In TypeScript this is usually referred to as a type brand (nominal typing) and there is a way to be more sneaky about it:
// inside the `Name.ts` moduledeclareconstvalidName:uniquesymbol;// export type Name = …typeName=string&{[validName]:true;};// exportfunctionassertValidName(value:string):assertsvalueisName{if(!/^[a-zA-Z ]*$/.test(value))thrownewError(`Invalid name ${value}, Should consist of Alphabetical characters and spaces only`);if(value.length<2||100<value.length)thrownewError(`Invalid name S{value}: Should be 2-100 characters long`);}/*
Assertion Functions:
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#assertion-functions
*/// In another moduleconsttryName='valid Name';assertValidName(tryName);sendBirthdayInvitation(tryName,'someone@gmail.com',30);//// works; `tryName` is now typed as// const tryName: "valid Name" & {// [validName]: true;// } constinvalidName='Inv@lid n@m3';assertValidName(invalidName);// Error: invalid name Inv@lid n@m3, Should consist of Alphabetical characters and spaces onlysendBirthdayInvitation(invalidName,'someone@gmail.com',30);constanotherTry='Inv@lid n@m3';sendBirthdayInvitation(anotherTry,'someone@gmail.com',30);// Transpilation error:// Argument of type 'string' is not assignable to parameter of type 'Name'.// Type 'string' is not assignable to type '{ [validName]: true; }'.(2345)functionsendBirthdayInvitation(senderName:Name,recipient:string,age:number){console.log(senderName);}
James Coplien
"How many of you do object-oriented programming? What language? Java is the only language in which you cannot do object-oriented programming. Huh? Other languages. Smalltalk - no. C# - no. Python - no. No. Any JavaScript programmers here? Here are my object-oriented programmers - they're writing objects - the rest of you are writing classes".
The fundamental idea behind a value object is that its identity is established by the contained values rather than the reference of the actual object.
"With Value Objects, we establish identity through the structural equality of two instances." Value Objects - DDD
Given that new Name('John Doe') !== new Name('John Doe') there really needs to be a comparison method (equals()) on the class that checks for structural equality or in the case of "objects as records" a comparison function.
JavaScript Tuples and Records (Stage 2, December 2021) may make that easier in the future.
Wow! it was worth putting the effort to write this article only to get this amazing feedback from you! Thank you for all this information.
Since this is an introductry article with the main goal of explaining the core principles of Value Objects, I prioritized understandability above all in my example implementation. So there are a few flaws in my implementation at the price of illustrating the concepts of Value Objects more clearly and keeping it readable for folks using other languages than TypeScript.
Have you ever written a project following Domain Driven Design with TypeScript? If so, please share with us how did you implement its principles? Did you use a dedicated library?
Sorry it was hard to read the code, I went with screenshots rather than code blocks because I wanted to show how the Value Object utilizes the IDE to make our lives much easier. Also, I thought it would be helpful if I highlight the last changes in each code snippet. Maybe I'll use a combination of code blocks and screenshots next time.
Yep, I got that Regex wrong 😅, I intentionally checked the length on a separate line for readability though.
An equals() method is definitely a must here. I did not want to go into equality comparison and how it diffrentiate between Value Objects and Entities since it's an introductory article.
Thank you for explaining type branding so clearly, I did come across the concept on my research but decided not to use it for the example in the article. If you use it you cannot use a base Value Object class though, how would you deal with that? Composition maybe?
illustrating the concepts of Value Objects more clearly and keeping it readable for folks using other languages than TypeScript.
It comes across as if you actually mean "class-based object oriented" languages rather than languages in general.
Domain-Driven Design: Tackling Complexity in the Heart of Software was published in 2003 and was a product of its time. Java was dogmatically object-oriented but "values" where needed, so Eric Evans conceived the "Value Object". However now the broader spectrum of languages aren't constrained to objects. And neither is DDD constrained to OO.
While classes are types, not all types are classes. Many languages support tuples and records in such a way that they can serve as "Value Objects" even though they're not objects.
"TypeScript began its life as an attempt to bring traditional object-oriented types to JavaScript so that the programmers at Microsoft could bring traditional object-oriented programs to the web. As it has developed, TypeScript’s type system has evolved to model code written by native JavaScripters. The resulting system is powerful, interesting and messy." ref
So even TypeScript had to adapt. In JavaScript arrays often serve as tuples and plain objects as records or dictionaries; they are treated as values even though they have the runtime semantics of objects (not necessarily created by a class).
Have you ever written a project following Domain Driven Design with TypeScript?
No, likely because most TypeScript based projects still embrace the Smart UI philosophy as it fits the team's capabilities better.
Did you use a dedicated library?
DDD is an approach, a way of thinking and working, not a software tool. And in my experience frameworks often tend to make it harder to implement DDD because they prioritize the needs of the framework. I would even go as far as saying that tooling is largely responsible for the dominance of the Smart UI approach.
Now perhaps there may be domain specific libraries out there but that means
that someone already has done the hard work for you
you are locked into that library's opinion and may only discover much later that it isn't a good fit or prevents you from evolving into the direction that you need to go.
Maybe I'll use a combination of code blocks and screenshots next time.
I'd favor code blocks and use images only when absolutely necessary (perhaps augmented with links to something like codesandbox) Typically just code blocks will do because with images you should be supplying the alt text anyway.
I did not want to go into equality comparison and how it differentiate between Value Objects and Entities since it's an introductory article.
Structural equality is a key characteristic of values and value objects; so an introduction without that leaves the audience largely in the dark of the value that value objects bring.
If you use it you cannot use a base Value Object class though, how would you deal with that? Composition maybe?
I'm not sure I understand the question. I would need some convincing that using inheritance with value objects is even a good idea. And the technique you applied falls within the practice "type branding".
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
Please use code blocks instead of inaccessible images—the font is too small.
Your regular expression
'^[a-zA-Z ]$'
only passes only on single character names.'^[a-zA-Z ]{2,100}$'
takes care of everything.Until your favourite duct tape programmer comes along.
😁
In TypeScript this is usually referred to as a type brand (nominal typing) and there is a way to be more sneaky about it:
playground
credit
The
validName
property only exists at compile time so there is no runtime overhead.It is well worth looking beyond
class
/interface
intotype
, intersection types, and discriminated unions.James Coplien
"How many of you do object-oriented programming? What language? Java is the only language in which you cannot do object-oriented programming. Huh? Other languages. Smalltalk - no. C# - no. Python - no. No. Any JavaScript programmers here? Here are my object-oriented programmers - they're writing objects - the rest of you are writing classes".
The fundamental idea behind a value object is that its identity is established by the contained values rather than the reference of the actual object.
"With Value Objects, we establish identity through the structural equality of two instances."
Value Objects - DDD
Given that
new Name('John Doe') !== new Name('John Doe')
there really needs to be a comparison method (equals()
) on the class that checks for structural equality or in the case of "objects as records" a comparison function.JavaScript Tuples and Records (Stage 2, December 2021) may make that easier in the future.
Wow! it was worth putting the effort to write this article only to get this amazing feedback from you! Thank you for all this information.
Since this is an introductry article with the main goal of explaining the core principles of Value Objects, I prioritized understandability above all in my example implementation. So there are a few flaws in my implementation at the price of illustrating the concepts of Value Objects more clearly and keeping it readable for folks using other languages than TypeScript.
Have you ever written a project following Domain Driven Design with TypeScript? If so, please share with us how did you implement its principles? Did you use a dedicated library?
Sorry it was hard to read the code, I went with screenshots rather than code blocks because I wanted to show how the Value Object utilizes the IDE to make our lives much easier. Also, I thought it would be helpful if I highlight the last changes in each code snippet. Maybe I'll use a combination of code blocks and screenshots next time.
Yep, I got that Regex wrong 😅, I intentionally checked the length on a separate line for readability though.
An
equals()
method is definitely a must here. I did not want to go into equality comparison and how it diffrentiate between Value Objects and Entities since it's an introductory article.Thank you for explaining type branding so clearly, I did come across the concept on my research but decided not to use it for the example in the article. If you use it you cannot use a base Value Object class though, how would you deal with that? Composition maybe?
It comes across as if you actually mean "class-based object oriented" languages rather than languages in general.
Domain-Driven Design: Tackling Complexity in the Heart of Software was published in 2003 and was a product of its time. Java was dogmatically object-oriented but "values" where needed, so Eric Evans conceived the "Value Object". However now the broader spectrum of languages aren't constrained to objects. And neither is DDD constrained to OO.
While classes are types, not all types are classes. Many languages support tuples and records in such a way that they can serve as "Value Objects" even though they're not objects.
"TypeScript began its life as an attempt to bring traditional object-oriented types to JavaScript so that the programmers at Microsoft could bring traditional object-oriented programs to the web. As it has developed, TypeScript’s type system has evolved to model code written by native JavaScripters. The resulting system is powerful, interesting and messy."
ref
So even TypeScript had to adapt. In JavaScript arrays often serve as tuples and plain objects as records or dictionaries; they are treated as values even though they have the runtime semantics of objects (not necessarily created by a
class
).No, likely because most TypeScript based projects still embrace the Smart UI philosophy as it fits the team's capabilities better.
DDD is an approach, a way of thinking and working, not a software tool. And in my experience frameworks often tend to make it harder to implement DDD because they prioritize the needs of the framework. I would even go as far as saying that tooling is largely responsible for the dominance of the Smart UI approach.
Now perhaps there may be domain specific libraries out there but that means
Bring Clarity To Your Monolith with Bounded Contexts (Rails)
I'd favor code blocks and use images only when absolutely necessary (perhaps augmented with links to something like codesandbox) Typically just code blocks will do because with images you should be supplying the alt text anyway.
Structural equality is a key characteristic of values and value objects; so an introduction without that leaves the audience largely in the dark of the value that value objects bring.
I'm not sure I understand the question. I would need some convincing that using inheritance with value objects is even a good idea. And the technique you applied falls within the practice "type branding".