dev-resources.site
for different kinds of informations.
Stricter TypeScript >, <, and ===
TypeScript needs a new feature for Type aliases to allow stricter comparison for >, <, and ===. Possibly for Interface as well, but I donât think the demographic that utilizes Interface would care.
When creating Objects, JavaScript needs a valueOf method so it knows what to do with > and <.
2 > 1 // true, works with number
{} > {} // false, JavaScript doesn't know
{ valueOf: () => 2} > { valueOf: () => 1 } // true
When youâre creating type aliases, you donât create âmethodsâ; itâs just a Record; itâs data. For example, if you play with the JavaScript Stage 2 Record proposal, this generates a runtime type error that you cannot convert Records to Numbers:
const proposal1 = #{ name: 'cow' }
const proposal2 = #{ name: 'sup' }
console.log(proposal1 > proposal2)
Whereas, if you used regular Objects in our previous example, it works fine.
If you change an Array.sort methodâs compare function or an Array.filter from using a number to an Object, the code will still run, the results will be different because comparing 2 Objects with > and < always results in false. When using TypeScript like I did where you change a number to a type alias, any place in the code that uses those 2 Array methods will âstill workâ. Thankfully I had unit and acceptance tests that started failing despite TypeScript saying âall is wellâ.
The simplest way to fix this for > and < is to simply get Recordâs to Stage 3:
https://github.com/tc39/proposal-record-tuple
⌠which will in turn get TypeScript to implement them. Based on the possible new Dictionary type (think TypeScript Dictionary === JavaScript Record, TypeScript Record === JavaScript Object):
https://github.com/microsoft/TypeScript/issues/49243
⌠would mean I could convert this:
type Grant = { year: number }
To this and get the type safety for > and < operators:
type Grant = #{ year: number }
An example, if we take the code we have now, sorting an Array of numbers:
someGrantArray.sort( a:number, b:number ) => {
if(a > b) {
return -1
} else if(a < b) {
return 1
} else {
return 0
}
}
Then later refactor it to take a type alias:
type Grant = { year: number }
Then fix the compiler errors:
someGrantArray.sort( a:Grant, b:Grant ) => {
if(a > b) {
return -1
} else if(a < b) {
return 1
} else {
return 0
}
}
⌠that compiles, but results in always return 1. If you used Records, itâd at least fail at runtime. One point of TypeScript is to help prevent runtime exceptions via type safety. If you used the suggested Dictionary class in TypeScript, which like Records does not allow methods on the Records, which in turn means you cannot utilize a valueOf which in turn means TypeScript âknowsâ you canât convert a Record to a number, which means youâd get a compiler error. Thatâd be awesome.
However, that doesnât solve ===. If you have JavaScript comparing numbers:
const fund:number = 2019
someGrants.filter ( (year:number)=> year === fund )
Then refactor to use a type alias:
const fund:Grant = { year: 2019 }
someGrants.filter ( (year:Grant) => year === fund )
That code compiles, but is NOT what you want; the intent was âfilter by yearâ not âdo these Objects equal each otherâ. I recognize that equality has itâs own bag of complexity.
For example, using Discriminated Unions in TypeScript:
a = Ok(1)
b = Ok(1)
a == b // false
Whereas, using them in Elm:
a = Ok 1
b = Ok 1
a == b -- True
The TypeScript way makes sense to those who know JavaScript, or are used to an imperative/OOP language. To FP developers who are used to Sum types, the Elm way makes sense. The imperative/OOP developers think âitâs a unique instance, of course those 2 donât equal each other, theyâre different things, different memory addresses in RAMâ. The FP devs are âWhy does 1 not equal 1? If I write 1 != 1 in JavaScript, I get false, and if I write 1 == 1, I get true⌠so whatâs going on?â
Thatâs why a few of the FP libraries that support Discriminated Unions will encourage the use of pattern matching, like âmatchâ rather than rely on operators that werenât built for that style:
https://gcanti.github.io/fp-ts/modules/Either.ts.html
Fine, so FP devs can hide behind matchâs they have to build manually; but what about imperative/OOP devs? Maybe a ==== operator or perhaps a compiler setting for âstrict comparisonâ that flags the compiler to either look for valueOf on the interface, or maybe just a linting rule to prevent the use of == & === entirely?
Featured ones: