Optional
utility class in TypeScript, based on C++
std::optional
.
Made as minimally as I could, without any dependencies.
I just like how std::optional
works and wanted it in JS/TS.
Guess it’s mostly done unless I find some mistake or something. 🤷🏼♂️
import { Optional } from "@onegen/optional";
function safeDiv (x: number, y: number): Optional<number> {
if (y === 0) return Optional.nullopt;
return Optional.some(x / y);
}
var result = safeDiv(2, 0);
if (!result.hasValue())
console.log('Dividing be zero again, you dummy?');
else
console.log('Result:', result.value());
Optional
is a wrapper helper class around a value that may or may not
be defined. Instead of returning some arbitrary value (like -1),
null
or throwing an error, Optional
can be returned, prompting you
– the dev – to first check if there is any value before actually using it
in a fun and type safe manner! Look, it’s not for everyone, but I like it, OK?
import { Optional, some } from '@onegen/optional';
var opt1 = new Optional<number>(2024);
var opt2 = Optional.some(2024);
var opt3 = some(2024)
All of these lines are equivalent. They create an Optional
holding a number
value 2024. First line specifies the type explicitly, second implies it from
its value, third line is just a shorthand for the second.
As you – a smart TypeScript developer – might’ve guessed, you can’t change the
Optional
type. Once you make an instance of Optional<T>
, the variable will
only ever have Optional<T>
.
var opt = Optional.some(2024);
opt = Optional.some('2024'); // TS won’t let you do this!
You can change the value, of course:
var opt = Optional.some(2024);
opt = Optional.some(2025);
// ..or as of 1.1.0 with a method:
opt.assign(2026);
…and even remove it:
var opt = Optional.some(2024);
opt = Optional.none();
opt = Optional.nullopt; // equivalent to Optional.none()
Do mind that this doesn’t clear the variable type. The variable is still
Optional<number>
, even if nullopt
. It will ever contain only a number
or nothing.
Be mindful when creating empty Optional
s:
var opt = Optional.none()
The type of opt
is Optional<unknown>
and that is not something you really
want now. I wish I could somehow forbid this, but oh well. Seriously, don’t
do that. When making an empty Optional
, specify its type explicitly, for your
own sanity:
var opt: Optional<number> = Optional.none();
var opt = new Optional<number>();
Both these options work perfectly fine.
The main advantage of Optional
is that you don’t need an arbitrary
"did not work" value (-1) or use null
s that you may forgot to check for.
Optional
makes it natural (at least for me) to check if it has a value
before actually using it:
const result: Optional<number> = saferDivide(10, 0);
if (!result.hasValue())
return "Whoops, something went wrong!"
const value = result.value();
Calling result.value()
while there is no value will lead to an error.
If you want a more comprehensive Rust-like Result
utility for error handling,
you might want to take a look at
neverthrow.
It has a lot more functionality for error handling, Optional
is just a simple
"has value or has no value" wrapper. With a few more functions copied from
C++:
Function | Return Type | Description |
---|---|---|
Optional.hasValue() |
boolean |
Checks whether the object contains a value |
Optional.value() |
T |
Returns the included value (throws error if there is none) |
Optional.valueOr(defaultValue: T) |
T |
Returns either the included value OR provided default value |
Function | Return Type | Description |
---|---|---|
Optional.reset() |
this |
Removes the contained value |
Optional.assign() |
this |
Assigns a new contained value |
Optional.swap(other: Optional<T>) |
this |
Swaps values of same-type Optionals |
C++ also has emplace()
,
but TS types cannot be used to make new instances, as far as I know.
assign()
is also deviance from std::optional
, but I chose to add it, as TS/JS
does not allow operator overloading.
Also, all modifier methods return themselves (this
) to allow chaining.
var opt = Optional.some(2024);
opt.reset().assign(2025).reset();
Function | Return Type | Description |
---|---|---|
Optional.andThen<U> (fn: (value: T) => Optional<U>) |
Optional<U> |
– |
Optional.transform<U> (fn: (value: T) => U) |
Optional<U> |
– |
Optional.orElse (fn: () => Optional<T>) |
Optional<U> |
– |
These are harder to explain in short Markdown table, there are simple usage examples
in optional-mon.test.ts
. Who am I even writing this for
nobody will use this except me lmao.
@onegen/optional is available as an open-source utility library licenced under the MIT Licence.
- TL;DR;NAL: Do absolutely whatever you want with the code, just include the LICENCE file if you re-distribute it.
- See
LICENCE
file or tl;drLegal for more details.