Yutaka's blog

Empty string and nullable string

Nullable string has three states on a frontend code

Some programming languages allow us to have a nullable string value. On a frontend code, developers may have to consider the three states for a nullable string:

On a frontend code, developers usually make the script render HTML elements in accordance with provided values from its server-side. When a value is null, a component will be rendered with "No value is set." Also, it may display the same message if the value is empty. Of course, the null and an empty string are completely different, but practically, it makes sense to deal with them the same way when presenting the value on a page. So, it's not sufficient to just detect whether a passed value is null or not on a frontend code, and frontend developers must check whether the value is empty. Perhaps, if the null and an empty string are virtually the same, the server-side should change its API to return a string value: non-nullable string because a nullable string is redundant.

Is a nullable string always overkill?

If separated teams maintain a server-side and a frontend respectively, server-side developers don't have to care about a case in which an empty string should be handled differently from null. Rather, they should not think about it. Their concern is only whether a value is string or null. They are not aware that an empty string has a special meaning. If frontend developers and server-side developers shared this meaning, this value could be a string, not a nullable string. However, both sides will have to share a prerequisite that an empty string is special, and some documentation may be required. There would be no problem as long as the different teams can maintain this information continuously.

However, it would not be easy for server-side developers who have just joined the team to understand the special meaning. They might wonder why they have to set an empty string. They might think it should be null because the value is not unset.

On the other hand, a nullable string is obvious and understandable for many server-side developers, even for newcomers.

Example

Let's take a look at one example.

Server-side code will respond with this data type:

interface User {
  id: number,
  name: string,
  bio: string | null,
}

Meanwhile, frontend code will handle the data like this:

const user: User = await fetch('/users/123')

if (user.bio != null && user.bio.length > 0) {
  console.log(`${user.name}'s bio is ${user.bio}`)
} else {
  console.log(`${user.name}'s bio is unset.`)
}

As I described above, the frontend deals with the empty bio as the same as null. If the bio in User were string, the frontend code could be updated simply:

 const user: User = await fetch('/users/123')

-if (user.bio != null && user.bio.length > 0) {
+if (user.bio.length > 0) {
   console.log(`${user.name}'s bio is ${user.bio}`)
 } else {
   console.log(`${user.name}'s bio is unset.`)

And then, if frontend developers want to code without checking whether it's null, they have to share the information that the bio must be empty if it's unset.

Note I'm not discussing runtime checking. This code might still require user.bio != null because the data from the server-side is still uncertain in a runtime environment — it means data from the server-side is any.

Wrap up

A nullable string may force developers to code more with an extra check. If you want to remove it, you may have to share a specific state on a value among other developers — e.g., a case that an empty string is special.