FP Utility Methods
The last page described directly using the fields of Data<T>
and other FP
interfaces
to interact with their content.
However, many times you can use the FP
utility methods to better interact with returned data.
mapIf
mapIf
allows transforming the data of an FP
, operating like the .then
method on a Promise.
Specify the kind of data you’re transforming by either providing a class or the value of "kind"
,
and a transformation function.
-
If the object matches the
kind
specified-
and the function returns an
FP
, the return value will be used -
and the function returns raw data, the data will be wrapped in
Data
and returned
-
-
If the object does not match the
kind
, it will be returned as-is
new EntityNotFound<number, "number">("number")
.mapIf(
EntityNotFound, (1)
notFound => new UnexpectedError(notFound),
);
// => UnexpectedError (2)
new Data(10).mapIf(
"data", (3)
data => data.data + 10, (4)
);
// => Data<number>
new Data(10).mapIf(EntityNotFound, () => {
throw new Error("This will never match.");
});
// => Data<number>
1 | This example passes a class to match |
2 | Because the class matches, the data is transformed |
3 | Alternatively, you can match by name |
4 | See mapData for a shortcut when mapping Data objects |
mapData
mapData
is a useful shortcut used when an FP
may be a Data
instance, and works similar to calling .then
on a Promise.
The function given to mapData
will be provided the contents of the Data
object.
-
If
mapData
is called on a non-Data
object, the object will be returned as-is -
If the function passed to
mapData
returns anFP
object (haskind
), the returned value will be passed as-is -
If the function returns any other object, it will be wrapped in
Data
interface User {
id: number;
username: string;
}
/** Case 1: mapData does not transform objects that are not Data<T> */
new AccessForbidden<User, "User">("User").mapData(x => {
throw new Error("This can never be reached.");
}); // => AccessForbidden<User, "User">
/**
* Case 2: an FP<T> object will be returned as-is
* (e.g. you can return Data<T> and it won't be wrapped as Data<Data<T>>)
*/
new Data<User>({ id: 1234, username: "admin" }).mapData(user => {
if(user.username === "admin") {
return new AccessForbidden("User");
}
return user;
}); // => Data<User> | AccessForbidden<User, "User">
/**
* Returning raw data will be wrapped in a new `Data<T>` object.
*/
new Data(5).mapData(x => x + 10) // => Data<number>.data = 15
mapDataAsync
mapDataAsync
is like mapData
, but uses Promises.
async function getUser(username: string): Promise<Data<User> | EntityNotFound<User, "User">> { /* ... */ }
async function getUserProfile(user: User): Promise<Data<Profile> | MissingPermission<Profile>> { /* ... */ }
async function main() {
const user = await getUser("admin");
const profile = await user.mapDataAsync(user => getUserProfile(user));
// => Data<Profile> | MissingPermission<Profile> | EntityNotFound<User, "User">
}