Nowadays I mostly code in Kotlin programming language. I got interested in it when I started working on a Java 7 codebase and quickly got fed up with the language. At Bright Inventions we often use TypeScript for both back-end, front-end and mobile development so I thought I would share some thoughts and tips for TypeScript learned while using Kotlin. In particular this post is about constant variables.
Use const
whenever possible
Using immutable variables aids reasoning about the flow and state of a program. It helps compiler to provide more intelligent hints especially while dealing with nullable types.
In Kotlin a val
keyword denotes a variable which value does not change after initialization e.g.:
val x: Int
val y = 3
x = 2
x = 20 // Error: Val cannot be reassigned
y = 30 // Error: Val cannot be reassigned
In TypeScript such a situation is handled with const
:
const x: number // Error: 'const' declarations must be initialized
const y: number = 3
y = 30 // Error: Cannot assign to 'y' because it is constant or read-only property
Compilers love const
The first way in which the compiler gets smarter when we use const
are null checks. When you enable strictNullChecks
, which you should, both Kotlin and TypeScript compiler understand if something can or cannot be null.
const firstName: string | null = getFirstName()
let lastName: string | null = getLastName()
if (firstName !== null && lastName !== null) {
setTimeout(() => {
console.log(firstName.length)
console.log(lastName.length) // Error: Object is possibly 'null'
})
}
In the first 2 lines we declare firstName
and lastName
as holding string
or null
. The variables are initialized with the helper functions getFirstName
and getLastName
. After we check that firstName
and lastName
are definitely not null we fire some async function. We can safely use firstName.length
. However, when we use lastName.length
the compiler complains with Object is possibly 'null'
error. This is because it is possible that in between the null check and the console.log
statement something could change the lastName
value. We might know that this is not true just by looking at the code. The compiler however, cannot be 100% sure in all cases. Thankfully we have const
and we can share our knowledge with the compiler.
Compilers catch bugs with const
Because const
and val
can only be assigned once, compilers can prevent another class of bugs. Take a look at the code example blow. There is a bug 🐛 that could easily be avoided had we used const
instead of let
.
let firstName: string = person.firstName
let lastName: string = person.lastName
const parsed = parseFormData((data: {name: string }) => {
let first: string | null, last: string | null
let parts = data.name.split(' ')
lastName = parts[0]
firstName = parts[1]
return { firstName: first, lastName: last }
})
if (parsed.firstName !== firstName || parsed.lastName !== lastName) {
// submit changes
}
You may have spotted the bug. Chances are though, especially if you are like me, that after long hours when the coffee level in your blood drops substantially below the required level, it will take long minutes to figure out the cause. There is a very easy remedy though. With firstName
and lastName
declared as constant variables the compiler catches bugs for us:
lastName = parts[0] // Error: Cannot assign 'lastName' because it is a constant or a read-only property
firstName = parts[1] // Error: Cannot assign 'firstName' because it is a constant or a read-only property