Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/robertmassaioli/ts-is-present
Solves the TypeScript filtering of undefined and null issue, amongst others: https://github.com/microsoft/TypeScript/issues/16069#issuecomment-565658443
https://github.com/robertmassaioli/ts-is-present
optionals presence typescript
Last synced: 3 days ago
JSON representation
Solves the TypeScript filtering of undefined and null issue, amongst others: https://github.com/microsoft/TypeScript/issues/16069#issuecomment-565658443
- Host: GitHub
- URL: https://github.com/robertmassaioli/ts-is-present
- Owner: robertmassaioli
- Created: 2020-08-23T04:09:53.000Z (about 4 years ago)
- Default Branch: master
- Last Pushed: 2023-01-07T04:55:05.000Z (almost 2 years ago)
- Last Synced: 2024-04-26T07:02:52.732Z (7 months ago)
- Topics: optionals, presence, typescript
- Language: TypeScript
- Homepage:
- Size: 278 KB
- Stars: 65
- Watchers: 2
- Forks: 2
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# ts-is-present
The `ts-is-present` package provides common functions to let you filter out the `null` or `undefined`
values from arrays in your code AND end up with the types that you expect.## Super short explanation
Install: `npm install --save ts-is-present`
``` typescript
import { isPresent, isDefined, isFilled } from 'ts-is-present';arrayWithUndefinedAndNullValues.filter(isPresent)
arrayWithUndefinedValues.filter(isDefined)
arrayWithNullValues.filter(isFilled)
```In a nutshell:
- `isPresent`: Removes `undefined` and `null` values via a `filter`.
- `isDefined`: Removes `undefined` values via a `filter`.
- `isFilled`: Removes `null` values via a `filter`.
- `hasPresentKey`: Removes everything that is not an object with the expected key present via a `filter`.
- `hasValueAtKey`: The same as `hasPresentKey` but with an additional check for a particular value.## Short explanation
The following code feels like it should type check, but it does not:
![Failing code](https://i.imgur.com/d8EBtg6.png)
It fails because the TypeScript type checker can't intuit that the lambda function eliminates the undefined values:
![Reasons for failing code](https://i.imgur.com/32biELe.png)
This library provides the three `isPresent`, `isDefined` and `isFilled` functions to solve this issue in the way that you would
expect the `filter` function to work:![Working code](https://i.imgur.com/WqgHTrU.png)
Use this library to dramatically simplify your TypeScript code and get the full power of your types.
## Use `isPresent` to drop all `Nothing` values
The `isDefined` and `isFilled` functions are only useful if you want `null` or `undefined` results to remain respectively
after you have performed some filtering operations. However, `isPresent` filters any values that represent nothing
from your results (`null`, `undefined` or `void`), like so:``` typescript
import { isPresent } from 'ts-is-present';type TestData = {
data: string;
};function getVoid(): void {
return undefined;
}const results: Array = [
{ data: 'hello' },
undefined,
{ data: 'world' },
getVoid(),
null,
{ data: 'wow' },];
const definedResults: Array = results.filter(isPresent);
```As you can see, `isPresent` can drop `undefined`, `null` and `void` values from an array (where `void` values are
really just `undefined` in disguise). This makes it broadly applicable.## Use `hasPresentKey` and `hasValueAtKey` to filter objects
If you want to find all of the objects in an array that have a particular field present, you can use `hasPresentKey`. For example:
``` typescript
const filesWithUrl = files.filter(hasPresentKey("url"));
files[0].url // TS will know that this is present
```If you want to find all of the objects with a particular field set to a particular value you can use `hasValueAtKey`:
``` typescript
type File = { type: "image", imageUrl: string } | { type: "pdf", pdfUrl: string };
const files: File[] = ;const filesWithUrl = files.filter(hasValueKey("type", "image" as const));
files[0].type // TS will now know that this is "image"
```These functions are useful in filtering out objects from arrays.
## Deeper Explanation
An example of the fundamental problem can be [found in the TypeScript bug tracker](https://github.com/microsoft/TypeScript/issues/16069)
but we will try and explain it again simply here.Firstly, TypeScript can not look at the following
lambda function `x => x !== undefined` and derive the type `(t: T | undefined): t is T`.
Instead, the best it can do is to derive the type: `(t: any): boolean`.Secondly, TypeScript has two type definitions for the `filter` function. They are:
``` typescript
// Definition 1
filter(callbackfn: (value: T, index: number, array: T[]) => value is S, thisArg?: any): S[];
// Definition 2
filter(callbackfn: (value: T, index: number, array: T[]) => unknown, thisArg?: any): T[];
```If we look at those types carefully they differ in an interesting way.
The second definition expects a callback function where the return type of that callback is `unknown`;
this will be treated as a truthy value when the filtering is performed. Most importantly, in this
function, if you give it an `Array` then you will get back an `Array`; even if the lambda
that you provided "proves" that the type could be restricted further.The first definition, however, expects that the return type of the callback will be `value is S`
where the generic definition of `S extends T` applies. This means that, if you give this version of
filter an `Array` and a function that can tell if a particular `T` is actually of the more restrictive
type `S` then it will give you back an `Array`. This is the critical feature of the `filter` type definitions
that lets the functions defined in this library refine the types inside a filter.In short, when you write the following code the second `filter` definition is used:
``` typescript
results.filter(x => x !== undefined)
```However, when you use this library the first `filter` definition is used:
``` typescript
results.filter(isDefined)
```That is why this library helps you derive the types you expect.
## Contributors
- [Jack Tomaszewski](https://github.com/jtomaszewski)
- [Robert Massaioli](https://github.com/robertmassaioli) (Maintainer)