I was looking at a great talk on Functional TypeScript by Thiago Temple in which he goes over a use-case (and general reason) for not using null
whenever possible, but instead enforcing stricter type-checking to cater for empty return types in a homogenous manner.
A value of null
can have any number of meanings, including but not limited to:
- Value not found
- An error has occurred
- Unpredicted case
- Value not required
- Value is falsy
null
therefore hides contextual meaning whenever it’s used. Consider the following function:
function findUserById(id: string): User | null {
// ...
}
If null
is returned, then it could mean either of the following:
- the User could not be found
- an Error has occurred
Since null
doesn’t provide any clarity, creating an Option
type that itself unions a generic Some
type and None
type that are created can help to give meaning to the output:
type Option<T> = Some<T> | None;
type Some<T> = {
kind: "someOption";
value: T;
}
type None = {
kind: "noneOption";
}
With these types crated, the findUserById
function’s output will provide clarity by indicating either one of two options are present in the response; a clear value (of type Some
) or no value (of type None
):
function findUserById(id: string): Option<User> {
// ...
}
Further, because of the kind
property is shared between the two types, it can be inspected and used for conditional logic:
const user = findUserById;
if (user.kind === "someOption") {
user.value;
// ...
}
#TIL
#TheMoreYouKnow