Utils functions to use with Task.
isInstanceOf(Constructor1, Constructor2, ...) => (instance: any) => instance is Constructor1 | Constructor2 | ...
It is an util function to use with caseError
. isInstanceOf
takes any number of constructors (or classes) and returns a function that tells us if an object is an instance of any of those constructors. In case it is, it is also typed as well (see type guards).
class Dog {
bark () {
return 'WOOF!';
}
}
class Cat {
meow () {
return 'Meeeeeoooooooow';
}
}
const isDog = isInstanceOf(Dog);
// This example is only for demonstration porpuses.
// I should actually prefer the animals to be polymorphic.
const talk = (animal: Dog | Cat) => {
if (isDog(animal)) {
// animal is typed as Dog
animal.bark();
}
else {
// animal is typed as Cat
animal.meow();
}
}
caseError(predicate, errHandler)
caseError
takes a predicate (a function to a boolean
) and an error handler. If predicate
returns true
when called with the rejected error, then errHandler
is called with the error and it's return value is returned. Else, the rejected error is rejected again.
import { Task } from '@ts-task/task';
import { caseError } from '@ts-task/utils';
// rejectedTask is a Task<never, FooError | BarError>
const rejectedTask = Task.reject(
Math.random() > 0.5 ?
new FooError() :
new BarError()
);
rejectedTask
.catch(err =>
// err is FooError | BarError
Task.reject(err)
)
.catch(
caseError(
isInstanceOf(FooError),
err =>
// err is a FooError
Task.resolve('foo ' + err.toString())
)
)
.catch(err =>
// err is a BarError (since the FooError case was resolved)
Task.reject(err)
)
;
Note: have in mind that TypeScript does duck typing checks, hence
FooError
andBarError
should have different properties to let TypeScript infere they are different, since TypeScript has structural typing instead of nominal typing.
toPromise(task)
toPromise
function naturally transforms a Task
into a Promise
.
import { Task } from '@ts-task/task';
import { toPromise } from '@ts-task/utils';
// resolvedTask is a Task<number, never>
const resolvedTask = Task.resolve(9);
// resolvedPromise is Promise<number>
const resolvedPromise = toPromise(resolvedTask);
// rejectedTask is a Task<never, Error>
const rejectedTask = Task.resolve(new Error());
// rejectedPromise is Promise<never>, rejected with Error
const rejectedPromise = toPromise(rejectedTask);
task.pipe(share())
As Tasks
are lazy, the Task
's code isn't executed until it's resolved. But, for the same reason the Task
's code is executed each time it is fork
ed (operators - including .map
, .chain
and .catch
methods - do fork
the Task
). share
function is an operator that resolves the Task
to that point and returns a Task
resolved (or rejected) with that value, so original Task
's code is executed only once.
import { Task } from '@ts-task/task';
import { share } from '@ts-task/utils';
const task = new Task<string, never>(resolve => {
console.log('Task\'s code is called');
resolve('Foo');
});
const sharedTask = task
.pipe(share);
sharedTask.fork(err => console.log(err), val => console.log(val));
sharedTask.fork(err => console.log(err), val => console.log(val));
sharedTask.fork(err => console.log(err), val => console.log(val));
// The message "Task's code is called" will be logged only once (even when forking multiple times).
Gonzalo Gluzman 💻 📖 |
Hernan Rajchert 💻 🎨 📖 🤔 |
---|
This project follows the all-contributors specification. Contributions of any kind are welcome!