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 saferDiv (x: number, y: number): Optional<number> {
if (y === 0) return Optional.nullopt;
return Optional.some(x / y);
}
var result = saferDiv(2, 0);
if (!result.hasValue())
console.log('Dividing by zero again, you dummy?');
else
console.log('It’s ', 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.
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!While you can’t change the type, you can, of course, change the value:
opt.assign(2026); // with a method, or
opt = Optional.some(2025); // by re-assigning…and even remove it:
opt.reset(); // with a method, or
opt = Optional.none(); // by re-assigning
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 Optionals:
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. Seriously, don’t do this.
When making an empty Optional, specify its type explicitly, for your
own sake:
var opt: Optional<number> = Optional.none();
var opt = new Optional<number>();The main advantage of Optional is that you don’t need an arbitrary
"did not work" value (-1) or use nulls 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.
This little utility is not attempting to be Rust Result. If you want a more
robust error-handling utility, you might want to take a look at
neverthrow.
Fully recommend (not sponsored).
| 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
LICENCEfile or tl;drLegal for more details.
