FRL TypeScript utils
This little project contains a few quality-of-life TypeScript utilities.
A. Installation
If you are using npm
, then simply run the npm install frl-ts-utils
CLI command to get the latest version.
If you are using yarn
, then go with the yarn add frl-ts-utils
command.
B. Types
-
Comparer<T> - represents a comparer delegate of two objects of type
T
. -
DeepReadonly<T> - represents a deep readonly
T
type. -
IDeepReadonlyArray<T> - an interface that extends the
ReadonlyArray<DeepReadonly<T>>
interface. -
IDeepReadonlyMap<K, V> - an interface that extends the
ReadonlyMap<DeepReadonly<K>, DeepReadonly<V>>
interface. -
IDeepReadonlySet<T> - an interface that extends the
ReadonlySet<DeepReadonly<T>>
interface. -
Delegate<TArgs, TReturnType> - represents a delegate type, that returns
TReturnType
and has parameters with types represented by theTArgs
tuple. -
ExtractDelegate<T> - allows to extract
Delegate<TArgs, TReturnType>
type fromT
. -
EmptyObject - represents an object with no properties.
-
Ensured - removes
null
andundefined
from typeT
. -
EqualityComparer<T> - represents an equality comparer delegate of two objects of type
T
. -
KeyOfType<TType, TPropertyType> - represents names of
TType
members that are ofTPropertyType
type. -
MethodKeyOf<TType> - represents names of
TType
members that are ofFunction
type. -
PropertyKeyOf<TType> - represents names of
TType
members that are not ofFunction
type. -
RequiredKeyOf<TType> - represents names of
TType
members that are not nullable and not undefinable. -
OptionalKeyOf<TType> - represents names of
TType
members that are nullable and/or undefinable. -
RequiredKeyOfType<TType, TPropertyType> - represents names of
TType
members that are not nullable and not undefinable, and that are ofTPropertyType
type. -
OptionalKeyOfType<TType, TPropertyType> - represents names of
TType
members that are nullable and/or undefinable, and that are ofTPropertyType
type. -
MemberKey - represents a union type of
string
,number
andsymbol
. -
None - represents a union type of
null
andundefined
. -
NotNull<T> - removed
null
from typeT
. -
NotUndefined<T> - removed
undefined
from typeT
. -
Nullable<T> - represents a union type of
T
andnull
. -
ObjectType<T> - represents a constructor of type
T
. -
AbstractObjectType<T> - represents a constructor of an abstract type
T
. -
Optional<T> - represents a union type of
T
,null
andundefined
. -
Primitive - represents a union type of
string
,number
andboolean
. -
PrimitiveTypesMap - represents a name-to-type map for primitive types.
-
PrimitiveTypeNames - represents a union of primitive type names.
-
Ref<T> - represents a reference type for value type
T
. -
Reject<T, K> - represents a type with all properties from
T
, without properties with keys fromK
. -
Replace<T, U> - represents a type with all properties from
T
, where properties with the same key as in theU
type are replaced by theU
type. -
Stringifier<T> - represents a delegate that converts an object of type
T
tostring
. -
TypeInstance<TType> - represents an instance type of either an
ObjectType<T>
orPrimitiveTypeNames
type. -
Undefinable<T> - represents a union type of
T
andundefined
.
C. Functions
-
makeRef<T> - creates a new
Ref<T>
object with the provided value. -
toDeepReadonly<T> - casts an object of type
T
to typeDeepReadonly<T>
. -
isDisposable - checks whether or not an object implements an
IDisposable
interface by having a method calleddispose
. -
Assert - a namespace containing a few useful assertion functions. These assertion functions either pass and return the provided parameter (except for Assert.True and Assert.False functions) or throw an
Error
. -
createIterable<T> - creates an
Iterable<T>
object from the provided iterator factory. -
deepFreeze<T> - recursively deep freezes the provided object and its properties, and returns it as
DeepReadonly<T>
. -
dynamicCast<T> - allows to safely cast an object to the specified type, otherwise returns
null
. Works for object and primitive types.
A few examples:
;// returns foo as a Bar object;// returns null;// returns null as well; ;// returns obj as a string;// returns null;// returns null as well;
It works for generic types too, however the generic parameters won't be validated:
; // returns foo as a Generic<string> object// note, how the result type has to specified explicitly// otherwise, the resulting type would be Generic<unknown>// which may, or may not be, something you want; ;// returns null;
-
isOfType<T> - allows to check, if an object is of specified type. Works for object and primitive types. This is very similar to the
dynamicCast<T>
function, however, instead of returning a cast object ornull
, it returnstrue
orfalse
instead, respectively. -
extend<T> - creates a function extension.
-
instanceOfCast<T> - allows to safely cast an object to the specified type, otherwise returns
null
. Works for object types only.
An example:
;// returns foo as a Bar object;// returns null;
Similar to dynamicCast<T>
, it works for generic types too:
; // returns foo as a Generic<string> object// note, how the result type has to specified explicitly// otherwise, the resulting type would be Generic<unknown>// which may, or may not be, something you want; ;// returns null;
-
isInstanceOfType<T> - allows to check, if an object is of specified type. Works for object types only. This is very similar to the
instanceOfCast<T>
function, however, instead of returning a cast object ornull
, it returnstrue
orfalse
instead, respectively. -
isDefined<T> - returns
true
, if an object is notnull
and notundefined
, otherwise returnsfalse
. -
isNull<T> - returns
true
, if an object isnull
, otherwise returnsfalse
. -
isUndefined<T> - returns
true
, if an object isundefined
, otherwise returnsfalse
. -
primitiveCast<T> - allows to safely cast an object to the specified type, otherwise returns
null
. Works for primitive types only.
An example:
;// returns obj as a string;// returns null;
-
isPrimitiveOfType<T> - allows to check, if an object is of specified type. Works for primitive types only. This is very similar to the
primitiveCast<T>
function, however, instead of returning a cast object ornull
, it returnstrue
orfalse
instead, respectively. -
readonlyCast<T> - allows to force cast a
Readonly<T>
object toT
type.
Be careful while using this function, since Readonly objects are probably marked as readonly for a reason (or are frozen) and are not supposed to be mutated within the scope. -
deepReadonlyCast<T> - allows to force cast a
DeepReadonly<T>
object toT
type.
Be careful while using this function, since DeepReadonly objects are probably marked as deep readonly for a reason (or are deep-frozen) and are not supposed to be mutated within the scope. -
reinterpretCast<T> - allows to force cast an object to the specified type.
Be very careful while using this function, because it allows you to cast any object to any type, which may cause the compilation process not to catch an obvious error.
An example:
;// this is a valid usage, however unfortunate it may be;result.trim; // runtime error, instead of a compilation error
-
using<T> - performs an action on an
IDisposable
object, and disposes it right after. -
usingAsync<T> - performs an asynchronous action on an
IDisposable
object, and disposes it right after. -
wait - creates a promise that resolves after the specified amount of time (in milliseconds).
D. Classes & Interfaces
- DeferredAction<TArgs> - represents an action that should be invoked after a specified amount of time has passed. This class allows e.g. to create a simple debouncing mechanism, since every new invocation request resets the timer.
An example:
// creates an action that executes after ~100ms; // invokes the action and starts the timeout// after ~100ms, 'action invoked' 'foo' will be logged to the console...deferred.invoke'foo'; // ... unless, the stop method is called before the timeout finishes, or...deferred.stop; // ... another invocation is calleddeferred.invoke'bar';
-
IDisposable - represents a disposable object.
-
Flag<T> - represents a simple flag or switch object, whose value can be changed.
An example:
// creates a boolean flag with initial value set to false; // update method allows to change the flag's valueflag.updatetrue; // exchange also changes the flag's value, however, it also returns the old value// here, the old variable will be equal to true; // current will be equal to false;
- Lazy<T> - represents a lazily initialized object.
An example:
// creates a new lazy object; // isCreated will be equal to false, since value hasn't been initialized yet; // calling value property's getter will invoke the provider and return 'foo'// subsequent calls to value's getter will no longer call the provider,// since the lazy object will cache its result;
-
Mixin<T> - represents a mixin object that can be merged together with other objects.
-
RepeatedAction<TArgs> - represents a stoppable action that is continuously invoked at a specified interval. This class allows e.g. to create a simple polling mechanism, that stops after a desired result has been achieved.
An example:
; // creates an action that executes every ~100ms, while i < 100; // invokes the action and starts the interval// every ~100ms, 'action invoked' i 'foo' will be logged to the console...repeated.invoke'foo'; // ... unless, the stop method is called before the action invocation returns RepeatedActionResult.Done, or...repeated.stop; // ... another invocation is calledrepeated.invoke'bar';
-
Rng - represents a pseudorandom number generator.
-
Semaphore - represents a semaphore variable, that limits concurrent access to an asynchronous block of code. There also exists a Mutex class, that acts as a simple lock.
-
SkippableAction<TArgs> - represents an asynchronous action that skips all intermediate invocations.
An example:
; // creates a skippable action, that resolves after ~100ms; // invokes the action and starts resolving itskippable.invoke'foo'; // calling another invoke before the first invocation resolves causes the last invocation to be queued// it will be invoked immediately after the first one resolvesskippable.invoke'bar'; // this call will cause the invoke('bar') call to be skipped// once the invoke('foo') finishes, the invoke('baz') will start resolving nextskippable.invoke'baz'; // current allows to fetch the promise, that is currently being resolved// in this case, it will return the promise, that is a result of the invoke('foo') call;
- StopWatch - represents a simple stopwatch object that allows to measure the passage of time. Its accurracy is somewhat limited, so unless you are ok with measurement errors of up to
~50ms
, then this is not a tool for you.
Events
E.Contains event publishing and event subscription functionality.
-
IEvent<TArgs> - an interface representing a subscribable event.
-
IEventListener<TArgs> - an interface representing an event subscription.
-
EventHandler<TArgs> - an implementation of the
IEvent<TArgs>
interface. Additionally, allows to publish an event.
Examples:
// creates a new event handler with no subscriptions; // creates a new event subscriptionhandler.listenconsole.logsender, args; // publishes an event with null sender and 'foo' argumenthandler.publishnull, 'foo'; // disposing an event handler will automatically dispose all subscriptionshandler.dispose;
Operators
Event listeners are decorable with operators. By calling the decorate method, you can specify how to modify the listener's behavior.
Built-in operators are:
Example of operator application:
; // listen method returns a newly created event listener instance; // decorates the event listener with operators// this particular decoration will cause the listener// to skip first 3 event publications, and then// only events with args being equal to either 'foo' or 'bar'// will be sent further to the listener's delegatelistener.decorate skip3, filter.somex === args; // ignored by the listener, first skiphandler.publishnull, '1'; // ignored by the listener, second skiphandler.publishnull, '2'; // ignored by the listener, third skiphandler.publishnull, '3'; // caught by the listenerhandler.publishnull, 'foo'; // ignored by the listener due to filtering operatorhandler.publishnull, 'foobar'; // caught by the listenerhandler.publishnull, 'bar';
It's also possible to define custom operators. The operator must be a function with the following signature:
;
EventListenerOperator<TArgs> is a type representing a delegate, that returns an event delegate. It accepts two parameters:
-
next
- a delegate, that calls the next operator, or the listener's delegate, if no other operators have been queued up. -
listener
- a reference to the event's listener. Can be used e.g. to automatically dispose the listener from inside the operator, based on some condition.
Let's define a custom operator, that simply logs the published event's sender and args to the console, along with the provided title via the operator's parameter and the amount of operator invocations:
And that's our operator! Let's apply it now to an event listener:
handler.listenconsole.logsender, args .decoratelogToConsole'hello event!';
- MessageBroker - a generic collection of event handlers registered under user-defined names.
Logging
F.Contains logging functionality.
-
LogMessage - represents a logger message.
-
LogType - represents a logger message type.
-
ILogger - an interface representing a subscribable logger.
-
ILoggerListener - an interface representing a logger subscription.
-
Logger - an implementation of the
ILogger
interface.
Examples:
// creates a new logger with no listeners; // creates a new logger listenerlogger.listenconsole.log`[, ]: `; // logs a message// there are also a few more specialized methods, that log a messagelogger.logLogMessage.Information'foo'; // it's also possible to set the logger's levellogger.logLevel = LogType.Warning; // this message won't be logged due to the current logger's log level// being set to Warning or abovelogger.logInformation'bar'; // disposing a logger will automatically dispose all listenerslogger.dispose;
Mapping
G.Contains a simple object mapping functionality.
-
IMapper - an interface representing an object mapper.
-
Mapper - an implementation of the
IMapper
interface. Additionall,y allows to add new mapping definitions.
Examples:
// creates a new mapper without any mapping definitions; // registers mapping from number to stringmapper.add'number', 'string', x.toString; // registers mapping from string to numbermapper.add'string', 'number', ; // registers mapping from Foo to Barmapper.addFoo, Bar,; // returns '15'; // returns 8; // returns new Bar instance with value equal to '11'; // throws an error, since mapping from Bar to Foo is undefined; // it's also possible to define mappings between primitive types and class types// registers mapping from number to Foomapper.add'number', Foo, new Foox; // registers mapping from Foo to numbermapper.addFoo, 'number', x.value; // returns new Foo instance with value equal to 7; // returns 6;
In addition to the map
method, the IMapper
contains some other helpful mapping methods: mapNullable
, mapUndefinable
, mapOptional
and mapRange
. The first 3 perform mapping conditionally, only when the source object is not null
/undefined
(depending on the used method). mapRange
allows to map a collection of objects to another collection.
mapRange
examples:
// let's use the mapper from the previous example ; // returns an array with 3 new Foo instances// first Foo instance value is equal to 1// second Foo instance value is equal to 2// third Foo instance value is equal to 3; // the source collection doesn't have to contain objects of the same type// as long as all of its elements are mappable to the destination type// if at least one element is not mappable, then the mapRange method will throw; // returns an array with 3 new Foo instances// first Foo instance value is equal to 4// second Foo instance value is equal to 5// third Foo instance value is equal to 6;
Tasks
H.Contains an asychronous, cancellable task functionality.
-
ITask<T> - an interface representing an executable task.
-
TaskResult<T> - represents the task's result.
-
TaskState - represents the task's current state.
-
TaskContinuationStrategy - represents the task's continuation strategy. Used as an ITask.then method's parameter.
-
Task<T> - an implementation of the
ITask<T>
interface.
Examples:
// creates a new promise-based task instance// in Created state; // alternatively:// task = Task.FromResult('foo'); // executes the task, which changes its state to Running// returns the task's result of type TaskResult<string>; // since the task executed without any errors,// it will be in the Completed state // value will be equal to 'foo'; // create a task, that throws an error during its execution; // alternatively:// task = Task.FromError<string>(new Error()); // since the task throws an error,// its state will be changed to Faulted; // error will be equal to the Error instance provided// to the Promise.reject function;
There exists a static instance of a completed task, which can be useful in certain situations:
;
Tasks can also be cancelled by dedicated cancellation tokens, like so:
// creates a new cancellation token, that isn't cancelled yet; ; // cancels the token with an optional reasoncancellationToken.cancel'cancellation reason'; // since the task is cancelled via a token,// its state will be changed to Cancelled; // error will be of type TaskCancellationError; // it's also possible to cancel the token after a specified amount of time (in ms)cancellationToken.cancelAfter1000;
Another important functionality of ITask<T>
is the possibility to continue it with another task. This can be achieved by calling the ITask.then method, like so:
// first task; // continuation task// the result parameter represents the first task's result// which can be used to create the follow-up task; ; // value will be an array of strings, containing two elements: 'foo' and 'bar';
ITask.then method has an optional second parameter of type TaskContinuationStrategy. It specifies, in which scenarios to continue the first task, based on its state. By default, all task states are continued.
If a continuation task is not invoked due to the continuation strategy, then its state will be changed to Discontinued
.
Another useful ITask
methods are:
join
- runs mutliple tasks concurrently and returns a new task, that resolves after all tasks have been resolved (such a joined task can also be created by calling theTask.All
function).race
- runs multiple tasks concurrently and returns a new task, that resolves after any task has been resolved (such a race task can also be created by calling theTask.Any
function).map
- allows to map task's result to another type. It will only be executed for task's, that complete successfuly.
Collections
I.Contains a few useful collections and data structures, as well as some collection manipulation algorithms.
-
Enumerable<T> - represents an enumerable collection, which can be manipulated via its methods.
-
Heap<T> - represents a heap data structure.
-
Iteration - contains a few algorithms that allow to manipulate collections.
-
KeyedCollection<TKey, TEntity> - represents a keyed collections of entities.
-
List<T> - represents a linked list data structure.
-
Pair<T, U> - represents a pair of objects.
-
Queue<T> - represents a queue data structure.
-
Stack<T> - represents a stack data structure.
-
UnorderedMap<TKey, TEntity> - represents an unordered map data structure.
-
UnorderedSet<T> - represents an unordered set data structure.