Socket
Socket
Sign inDemoInstall

@rx-signals/store

Package Overview
Dependencies
2
Maintainers
1
Versions
94
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 3.0.0-rc45 to 3.0.0-rc46

dist/cjs/optional-lens.js

1

dist/cjs/index.js

@@ -22,2 +22,3 @@ "use strict";

__exportStar(require("./model-signals-factory"), exports);
__exportStar(require("./optional-lens"), exports);
__exportStar(require("./signals-factory"), exports);

@@ -24,0 +25,0 @@ __exportStar(require("./store"), exports);

137

dist/cjs/type-utils.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.toGetter = exports.fromLens = exports.fromLensAndValue = exports.fromValueAndLens = exports.getLens = exports.isOptionalLens = exports.pick = exports.isValidModelValidationResult = exports.patchModelValidationResult = exports.isResultWithInput = exports.merge = void 0;
exports.isValidModelValidationResult = exports.patchModelValidationResult = exports.isResultWithInput = exports.merge = void 0;
/* eslint-disable @typescript-eslint/naming-convention */

@@ -105,137 +105,2 @@ const store_utils_1 = require("./store-utils");

exports.isValidModelValidationResult = isValidModelValidationResult;
/**
* Takes a value `T` and a key `K`.
* If value is an `Array<A>` (`K` is enforced as number in this case), it returns `value[key]` as `A | undefined`.
* If value is a `Record<any, any>` (`K` is enforced as `keyof T` in this case), it returns `value[key]` as `T[K] | undefined`.
* Else it returns undefined.
*/
const pick = (value, key) => {
if (Array.isArray(value)) {
return value[key];
}
if (value !== null && typeof value === 'object') {
return value[key];
}
return undefined;
};
exports.pick = pick;
const optionalLensKind = '$OptionalLens$';
/**
* Typeguard to check, if the given value is an {@link OptionalLens}
*/
const isOptionalLens = (value) => (value === null || value === void 0 ? void 0 : value.kind) === optionalLensKind;
exports.isOptionalLens = isOptionalLens;
const _toLens = (get, key) => {
const newGet = (v) => (0, exports.pick)(get(v), key);
return {
kind: optionalLensKind,
get: newGet,
k: (k) => _toLens(newGet, k),
};
};
/**
* Get an `OptionalLens<T, T>` for type-safe access on arbitrarily nested properties of type `T`,
* where `T` might be a union of arbitrary types.
*
* Given the following type and values:
* ```ts
* type Test =
* | number
* | {
* a:
* | string
* | Array<
* | boolean
* | {
* x: number | Array<number>;
* }
* >;
* };
*
* const t1: Test = 42;
* const t2: Test = { a: 'Test3' };
* const t3: Test = { a: [true, { x: 7 }, { x: [1, 2, 3] }] };
* ```
*
* you could get the following results with optional-lenses:
* ```ts
* const lensA = getLens<Test>().k('a');
* const a1 = lensA.get(t1); // => undefined (inferred as undefined | string | Array<boolean | { x: number | Array<number>}>)
* const a2 = lensA.get(t2); // => 'Test3' (inferred as undefined | string | Array<boolean | { x: number | Array<number>}>)
* const a3 = lensA.get(t3); // => [true, { x: 7 }, { x: [1, 2, 3] }] (inferred as undefined | string | Array<boolean | { x: number | Array<number>}>)
*
* const lensA2X1 = lensA.k(2).k('x').k(1);
* const n1 = lensA2X1.get(t1); // => undefined (inferred as number | undefined)
* const n2 = lensA2X1.get(t2); // => undefined (inferred as number | undefined)
* const n3 = lensA2X1.get(t3); // => 2 (inferred as number | undefined)
* ```
*/
const getLens = () => {
const get = (value) => value;
return {
get,
k: (key) => _toLens(get, key),
};
};
exports.getLens = getLens;
/**
* Utility function to apply an `OptionalLens<T, P>` to a `T`
*/
const fromValueAndLens = (value) => (lens) => lens.get(value);
exports.fromValueAndLens = fromValueAndLens;
/**
* Utility function to apply a `T` to an `OptionalLens<T, P>`
*/
const fromLensAndValue = (lens) => (value) => lens.get(value);
exports.fromLensAndValue = fromLensAndValue;
/**
* If the first argument is an `OptionalLens`, this function behaves like `fromLensAndValue`,
* else it behaves like `fromValueAndLens`
*/
const fromLens = (valueOrLens1) => (valueOrLens2) => (0, exports.isOptionalLens)(valueOrLens1)
? valueOrLens1.get(valueOrLens2)
: valueOrLens2.get(valueOrLens1);
exports.fromLens = fromLens;
const _toGetter = (g) => ({
get: () => g(),
k: (key) => _toGetter(() => (0, exports.pick)(g(), key)),
});
/**
* Wraps the given value of type T in a `Getter<T>`.
* A `Getter<T>` can be used like a one-time ad-hoc version of an {@link OptionalLens}.
* In most cases however, using an {@link OptionalLens} is the better choice.
*
* Given the following type and values:
* ```ts
* type Test =
* | number
* | {
* x: Array<number>;
* a: {
* b: number;
* };
* | {
* a: {
* b: string;
* }
* }
* };
*
* let t1: Test = 42;
* let t2: Test = { x: [1, 2, 3] };
* let t3: Test = { a: { b: 'Test' } };
* ```
*
* you could get the following results with toGetter:
* ```ts
* const b1 = toGetter(t1).k('a').k('b').get(); // => undefined (inferred as number | string | undefined)
* const b2 = toGetter(t2).k('a').k('b').get(); // => undefined (inferred as number | string | undefined)
* const b3 = toGetter(t3).k('a').k('b').get(); // => 'Test' (inferred as number | string | undefined)
* const x1 = toGetter(t1).k('x').k(1).get(); // => undefined (inferred as number | undefined)
* const x2 = toGetter(t2).k('x').k(1).get(); // => 2 (inferred as number | undefined)
* const x3 = toGetter(t3).k('x').k(1).get(); // => undefined (inferred as number | undefined)
* ```
*/
const toGetter = (value) => _toGetter(() => value);
exports.toGetter = toGetter;
//# sourceMappingURL=type-utils.js.map

@@ -5,2 +5,3 @@ export * from './effect-result';

export * from './model-signals-factory';
export * from './optional-lens';
export * from './signals-factory';

@@ -7,0 +8,0 @@ export * from './store';

@@ -5,2 +5,3 @@ export * from './effect-result';

export * from './model-signals-factory';
export * from './optional-lens';
export * from './signals-factory';

@@ -7,0 +8,0 @@ export * from './store';

@@ -192,198 +192,1 @@ import { NoValueType } from './store-utils';

export declare const isValidModelValidationResult: <T>(modelValidationResult: ModelValidationResult<T, any>) => boolean;
/**
* Returns number in case `T` is an `Array`,
* else if `T extends Record<any, any>`, it returns the keys of it,
* else it returns never.
*/
export type ToKeys<T> = T extends Array<any> ? number : T extends Record<any, any> ? {
[K in keyof T]: K;
}[keyof T] : never;
/**
* Return type of the pick function.
*/
export type PickReturn<T, K extends ToKeys<T>> = T extends Array<infer A> ? A | undefined : T extends Record<any, any> ? K extends keyof T ? T[K] | undefined : never : undefined;
/**
* Takes a value `T` and a key `K`.
* If value is an `Array<A>` (`K` is enforced as number in this case), it returns `value[key]` as `A | undefined`.
* If value is a `Record<any, any>` (`K` is enforced as `keyof T` in this case), it returns `value[key]` as `T[K] | undefined`.
* Else it returns undefined.
*/
export declare const pick: <T, K extends ToKeys<T>>(value: T, key: K) => PickReturn<T, K>;
/**
* An `OptionalLens<T, P>` grants type-safe access on potential `P`, hence it can be used to
* get `P | undefined` from an arbitrary `T`, where `T` might be a union of arbitrary types.
*
* From an `OptionalLens<T, P>`, you can also retrieve a new `OptionalLens<P, P[K]>`, where K is a potential key of P.
* Use `getLens<T>()` to get an initial `OptionalLens<T, T>`.
*
* You can see `OptionalLens` as "universal optional chaining". While normal optional chaining only works on a `T | null | undefined`,
* the `OptionalLens` allows the type-safe access on arbitrary unions.
*
* E.g. given the following type and values:
* ```ts
* type Test =
* | number
* | {
* a:
* | string
* | Array<
* | boolean
* | {
* x: number | Array<number>;
* }
* >;
* };
*
* const t1: Test = 42;
* const t2: Test = { a: 'Test3' };
* const t3: Test = { a: [true, { x: 7 }, { x: [1, 2, 3] }] };
* ```
*
* you could get the following results with optional-lenses:
* ```ts
* const lensA = getLens<Test>().k('a');
* const a1 = lensA.get(t1); // => undefined (inferred as undefined | string | Array<boolean | { x: number | Array<number>}>)
* const a2 = lensA.get(t2); // => 'Test3' (inferred as undefined | string | Array<boolean | { x: number | Array<number>}>)
* const a3 = lensA.get(t3); // => [true, { x: 7 }, { x: [1, 2, 3] }] (inferred as undefined | string | Array<boolean | { x: number | Array<number>}>)
*
* const lensA2X1 = lensA.k(2).k('x').k(1);
* const n1 = lensA2X1.get(t1); // => undefined (inferred as number | undefined)
* const n2 = lensA2X1.get(t2); // => undefined (inferred as number | undefined)
* const n3 = lensA2X1.get(t3); // => 2 (inferred as number | undefined)
* ```
*/
export type OptionalLens<T, P> = {
get: (value: T) => P | undefined;
k: <K extends ToKeys<P>>(key: K) => OptionalLens<T, PickReturn<P, K>>;
};
/**
* Typeguard to check, if the given value is an {@link OptionalLens}
*/
export declare const isOptionalLens: <T, P>(value: any) => value is OptionalLens<T, P>;
/**
* Get an `OptionalLens<T, T>` for type-safe access on arbitrarily nested properties of type `T`,
* where `T` might be a union of arbitrary types.
*
* Given the following type and values:
* ```ts
* type Test =
* | number
* | {
* a:
* | string
* | Array<
* | boolean
* | {
* x: number | Array<number>;
* }
* >;
* };
*
* const t1: Test = 42;
* const t2: Test = { a: 'Test3' };
* const t3: Test = { a: [true, { x: 7 }, { x: [1, 2, 3] }] };
* ```
*
* you could get the following results with optional-lenses:
* ```ts
* const lensA = getLens<Test>().k('a');
* const a1 = lensA.get(t1); // => undefined (inferred as undefined | string | Array<boolean | { x: number | Array<number>}>)
* const a2 = lensA.get(t2); // => 'Test3' (inferred as undefined | string | Array<boolean | { x: number | Array<number>}>)
* const a3 = lensA.get(t3); // => [true, { x: 7 }, { x: [1, 2, 3] }] (inferred as undefined | string | Array<boolean | { x: number | Array<number>}>)
*
* const lensA2X1 = lensA.k(2).k('x').k(1);
* const n1 = lensA2X1.get(t1); // => undefined (inferred as number | undefined)
* const n2 = lensA2X1.get(t2); // => undefined (inferred as number | undefined)
* const n3 = lensA2X1.get(t3); // => 2 (inferred as number | undefined)
* ```
*/
export declare const getLens: <T>() => OptionalLens<T, T>;
/**
* Get a concrete `OptionalLens<T, P>` from an `OptionalLens<any, any>` (or never, if L is no `OptionalLens<any, any>`)
*/
export type ToLensType<L> = [L] extends [OptionalLens<infer T, infer P>] ? OptionalLens<T, P> : never;
/**
* Get a concrete `T` from an `OptionalLens<T, any>` (or never, if L is no `OptionalLens<any, any>`)
*/
export type ToLensInputType<L> = [L] extends [OptionalLens<infer T, any>] ? T : never;
/**
* Get a concrete `T` from an `OptionalLens<any, T>` (or never, if L is no `OptionalLens<any, any>`)
*/
export type ToLensOutputType<L> = [L] extends [OptionalLens<any, infer T>] ? T : never;
/**
* Get `T`, if `VL` is an `OptionalLens<T, any>`, else get `OptionalLens<VL, any>`
*/
export type ValueOrLens<VL> = [VL] extends [OptionalLens<any, any>] ? ToLensInputType<VL> : OptionalLens<VL, any>;
/**
* Get return type of `OptionalLens<T, PX>::get(T)`, if `X` is an `OptionalLens<any, any>`,
* else get the return type of `OptionalLens<T, PY>::get(T)`, if `Y` is an `OptionalLens<any, any>`,
* else never.
*/
export type FromLensReturn<X, Y> = [X] extends [OptionalLens<any, any>] ? ToLensOutputType<X> | undefined : [Y] extends [OptionalLens<any, any>] ? ToLensOutputType<Y> | undefined : never;
/**
* Utility function to apply an `OptionalLens<T, P>` to a `T`
*/
export declare const fromValueAndLens: <T>(value: T) => <L extends OptionalLens<T, any>>(lens: L) => ToLensOutputType<L> | undefined;
/**
* Utility function to apply a `T` to an `OptionalLens<T, P>`
*/
export declare const fromLensAndValue: <L extends OptionalLens<any, any>>(lens: L) => <T extends ToLensInputType<L>>(value: T) => ToLensOutputType<L> | undefined;
/**
* If the first argument is an `OptionalLens`, this function behaves like `fromLensAndValue`,
* else it behaves like `fromValueAndLens`
*/
export declare const fromLens: <X>(valueOrLens1: X) => <Y extends ValueOrLens<X>>(valueOrLens2: Y) => FromLensReturn<X, Y>;
/**
* Return type of the toGetter function.
* Like {@link OptionalLens}, a `Getter<T>` can be used for optional chaining on arbitrary union types.
* In contrast to {@link OptionalLens}, the initial `Getter<T>` must be obtained from a value of type `T`.
* You can thus use it as kind of ad-hoc lens for a one-time access. In most cases however,
* using an {@link OptionalLens} is the better choice.
*
* See `toGetter` documentation for example usage.
*/
export type Getter<T> = {
get: () => T;
k: <K extends ToKeys<T>>(key: K) => Getter<PickReturn<T, K>>;
};
/**
* Helper type to infer the concrete value type `T` wrapped by a `Getter<T>`
*/
export type ToGetterValue<T> = T extends Getter<infer V> ? V : never;
/**
* Wraps the given value of type T in a `Getter<T>`.
* A `Getter<T>` can be used like a one-time ad-hoc version of an {@link OptionalLens}.
* In most cases however, using an {@link OptionalLens} is the better choice.
*
* Given the following type and values:
* ```ts
* type Test =
* | number
* | {
* x: Array<number>;
* a: {
* b: number;
* };
* | {
* a: {
* b: string;
* }
* }
* };
*
* let t1: Test = 42;
* let t2: Test = { x: [1, 2, 3] };
* let t3: Test = { a: { b: 'Test' } };
* ```
*
* you could get the following results with toGetter:
* ```ts
* const b1 = toGetter(t1).k('a').k('b').get(); // => undefined (inferred as number | string | undefined)
* const b2 = toGetter(t2).k('a').k('b').get(); // => undefined (inferred as number | string | undefined)
* const b3 = toGetter(t3).k('a').k('b').get(); // => 'Test' (inferred as number | string | undefined)
* const x1 = toGetter(t1).k('x').k(1).get(); // => undefined (inferred as number | undefined)
* const x2 = toGetter(t2).k('x').k(1).get(); // => 2 (inferred as number | undefined)
* const x3 = toGetter(t3).k('x').k(1).get(); // => undefined (inferred as number | undefined)
* ```
*/
export declare const toGetter: <T>(value: T) => Getter<T>;

@@ -98,130 +98,2 @@ /* eslint-disable @typescript-eslint/naming-convention */

};
/**
* Takes a value `T` and a key `K`.
* If value is an `Array<A>` (`K` is enforced as number in this case), it returns `value[key]` as `A | undefined`.
* If value is a `Record<any, any>` (`K` is enforced as `keyof T` in this case), it returns `value[key]` as `T[K] | undefined`.
* Else it returns undefined.
*/
export const pick = (value, key) => {
if (Array.isArray(value)) {
return value[key];
}
if (value !== null && typeof value === 'object') {
return value[key];
}
return undefined;
};
const optionalLensKind = '$OptionalLens$';
/**
* Typeguard to check, if the given value is an {@link OptionalLens}
*/
export const isOptionalLens = (value) => (value === null || value === void 0 ? void 0 : value.kind) === optionalLensKind;
const _toLens = (get, key) => {
const newGet = (v) => pick(get(v), key);
return {
kind: optionalLensKind,
get: newGet,
k: (k) => _toLens(newGet, k),
};
};
/**
* Get an `OptionalLens<T, T>` for type-safe access on arbitrarily nested properties of type `T`,
* where `T` might be a union of arbitrary types.
*
* Given the following type and values:
* ```ts
* type Test =
* | number
* | {
* a:
* | string
* | Array<
* | boolean
* | {
* x: number | Array<number>;
* }
* >;
* };
*
* const t1: Test = 42;
* const t2: Test = { a: 'Test3' };
* const t3: Test = { a: [true, { x: 7 }, { x: [1, 2, 3] }] };
* ```
*
* you could get the following results with optional-lenses:
* ```ts
* const lensA = getLens<Test>().k('a');
* const a1 = lensA.get(t1); // => undefined (inferred as undefined | string | Array<boolean | { x: number | Array<number>}>)
* const a2 = lensA.get(t2); // => 'Test3' (inferred as undefined | string | Array<boolean | { x: number | Array<number>}>)
* const a3 = lensA.get(t3); // => [true, { x: 7 }, { x: [1, 2, 3] }] (inferred as undefined | string | Array<boolean | { x: number | Array<number>}>)
*
* const lensA2X1 = lensA.k(2).k('x').k(1);
* const n1 = lensA2X1.get(t1); // => undefined (inferred as number | undefined)
* const n2 = lensA2X1.get(t2); // => undefined (inferred as number | undefined)
* const n3 = lensA2X1.get(t3); // => 2 (inferred as number | undefined)
* ```
*/
export const getLens = () => {
const get = (value) => value;
return {
get,
k: (key) => _toLens(get, key),
};
};
/**
* Utility function to apply an `OptionalLens<T, P>` to a `T`
*/
export const fromValueAndLens = (value) => (lens) => lens.get(value);
/**
* Utility function to apply a `T` to an `OptionalLens<T, P>`
*/
export const fromLensAndValue = (lens) => (value) => lens.get(value);
/**
* If the first argument is an `OptionalLens`, this function behaves like `fromLensAndValue`,
* else it behaves like `fromValueAndLens`
*/
export const fromLens = (valueOrLens1) => (valueOrLens2) => isOptionalLens(valueOrLens1)
? valueOrLens1.get(valueOrLens2)
: valueOrLens2.get(valueOrLens1);
const _toGetter = (g) => ({
get: () => g(),
k: (key) => _toGetter(() => pick(g(), key)),
});
/**
* Wraps the given value of type T in a `Getter<T>`.
* A `Getter<T>` can be used like a one-time ad-hoc version of an {@link OptionalLens}.
* In most cases however, using an {@link OptionalLens} is the better choice.
*
* Given the following type and values:
* ```ts
* type Test =
* | number
* | {
* x: Array<number>;
* a: {
* b: number;
* };
* | {
* a: {
* b: string;
* }
* }
* };
*
* let t1: Test = 42;
* let t2: Test = { x: [1, 2, 3] };
* let t3: Test = { a: { b: 'Test' } };
* ```
*
* you could get the following results with toGetter:
* ```ts
* const b1 = toGetter(t1).k('a').k('b').get(); // => undefined (inferred as number | string | undefined)
* const b2 = toGetter(t2).k('a').k('b').get(); // => undefined (inferred as number | string | undefined)
* const b3 = toGetter(t3).k('a').k('b').get(); // => 'Test' (inferred as number | string | undefined)
* const x1 = toGetter(t1).k('x').k(1).get(); // => undefined (inferred as number | undefined)
* const x2 = toGetter(t2).k('x').k(1).get(); // => 2 (inferred as number | undefined)
* const x3 = toGetter(t3).k('x').k(1).get(); // => undefined (inferred as number | undefined)
* ```
*/
export const toGetter = (value) => _toGetter(() => value);
//# sourceMappingURL=type-utils.js.map
{
"name": "@rx-signals/store",
"version": "3.0.0-rc45",
"version": "3.0.0-rc46",
"description": "Reactive state- and effects-management with behaviors and event streams",

@@ -5,0 +5,0 @@ "author": "Gerd Neudert",

@@ -6,3 +6,3 @@ # _@rx-signals/store_

:warning: This documentation is work in progress for the upcoming 3.0.0 version.
There is however NO good reason to use 2.x over 3.0.0-rc45, so please start with the rc-version (3.0.0 will be the first version I'm going to advertise publicly, so it's more like a 1.0 in reality.).
There is however NO good reason to use 2.x over 3.0.0-rc46, so please start with the rc-version (3.0.0 will be the first version I'm going to advertise publicly, so it's more like a 1.0 in reality.).
2.x is deprecated and will NOT be maintained in any way.

@@ -15,3 +15,3 @@

**`npm install --save @rx-signals/store@3.0.0-rc45`**
**`npm install --save @rx-signals/store@3.0.0-rc46`**

@@ -18,0 +18,0 @@ ## Dependencies

@@ -5,2 +5,3 @@ export * from './effect-result';

export * from './model-signals-factory';
export * from './optional-lens';
export * from './signals-factory';

@@ -7,0 +8,0 @@ export * from './store';

@@ -325,286 +325,1 @@ /* eslint-disable @typescript-eslint/naming-convention */

};
/**
* Returns number in case `T` is an `Array`,
* else if `T extends Record<any, any>`, it returns the keys of it,
* else it returns never.
*/
export type ToKeys<T> = T extends Array<any>
? number
: T extends Record<any, any>
? {
[K in keyof T]: K;
}[keyof T]
: never;
/**
* Return type of the pick function.
*/
export type PickReturn<T, K extends ToKeys<T>> = T extends Array<infer A>
? A | undefined
: T extends Record<any, any>
? K extends keyof T
? T[K] | undefined
: never
: undefined;
/**
* Takes a value `T` and a key `K`.
* If value is an `Array<A>` (`K` is enforced as number in this case), it returns `value[key]` as `A | undefined`.
* If value is a `Record<any, any>` (`K` is enforced as `keyof T` in this case), it returns `value[key]` as `T[K] | undefined`.
* Else it returns undefined.
*/
export const pick = <T, K extends ToKeys<T>>(value: T, key: K): PickReturn<T, K> => {
if (Array.isArray(value)) {
return value[key];
}
if (value !== null && typeof value === 'object') {
return (<Record<K, any>>value)[key] as PickReturn<T, K>;
}
return undefined as PickReturn<T, K>;
};
/**
* An `OptionalLens<T, P>` grants type-safe access on potential `P`, hence it can be used to
* get `P | undefined` from an arbitrary `T`, where `T` might be a union of arbitrary types.
*
* From an `OptionalLens<T, P>`, you can also retrieve a new `OptionalLens<P, P[K]>`, where K is a potential key of P.
* Use `getLens<T>()` to get an initial `OptionalLens<T, T>`.
*
* You can see `OptionalLens` as "universal optional chaining". While normal optional chaining only works on a `T | null | undefined`,
* the `OptionalLens` allows the type-safe access on arbitrary unions.
*
* E.g. given the following type and values:
* ```ts
* type Test =
* | number
* | {
* a:
* | string
* | Array<
* | boolean
* | {
* x: number | Array<number>;
* }
* >;
* };
*
* const t1: Test = 42;
* const t2: Test = { a: 'Test3' };
* const t3: Test = { a: [true, { x: 7 }, { x: [1, 2, 3] }] };
* ```
*
* you could get the following results with optional-lenses:
* ```ts
* const lensA = getLens<Test>().k('a');
* const a1 = lensA.get(t1); // => undefined (inferred as undefined | string | Array<boolean | { x: number | Array<number>}>)
* const a2 = lensA.get(t2); // => 'Test3' (inferred as undefined | string | Array<boolean | { x: number | Array<number>}>)
* const a3 = lensA.get(t3); // => [true, { x: 7 }, { x: [1, 2, 3] }] (inferred as undefined | string | Array<boolean | { x: number | Array<number>}>)
*
* const lensA2X1 = lensA.k(2).k('x').k(1);
* const n1 = lensA2X1.get(t1); // => undefined (inferred as number | undefined)
* const n2 = lensA2X1.get(t2); // => undefined (inferred as number | undefined)
* const n3 = lensA2X1.get(t3); // => 2 (inferred as number | undefined)
* ```
*/
export type OptionalLens<T, P> = {
get: (value: T) => P | undefined;
k: <K extends ToKeys<P>>(key: K) => OptionalLens<T, PickReturn<P, K>>;
};
const optionalLensKind = '$OptionalLens$';
type KindedOptionalLens<T, P> = OptionalLens<T, P> & {
kind: typeof optionalLensKind;
};
/**
* Typeguard to check, if the given value is an {@link OptionalLens}
*/
export const isOptionalLens = <T, P>(
value: OptionalLens<T, P> | any,
): value is OptionalLens<T, P> => value?.kind === optionalLensKind;
const _toLens = <T, P, K extends ToKeys<P>>(
get: (value: T) => P,
key: K,
): KindedOptionalLens<T, PickReturn<P, K>> => {
const newGet = (v: T): PickReturn<P, K> => pick(get(v), key);
return {
kind: optionalLensKind,
get: newGet,
k: <NK extends ToKeys<PickReturn<P, K>>>(
k: NK,
): KindedOptionalLens<T, PickReturn<PickReturn<P, K>, NK>> =>
_toLens<T, PickReturn<P, K>, NK>(newGet, k),
};
};
/**
* Get an `OptionalLens<T, T>` for type-safe access on arbitrarily nested properties of type `T`,
* where `T` might be a union of arbitrary types.
*
* Given the following type and values:
* ```ts
* type Test =
* | number
* | {
* a:
* | string
* | Array<
* | boolean
* | {
* x: number | Array<number>;
* }
* >;
* };
*
* const t1: Test = 42;
* const t2: Test = { a: 'Test3' };
* const t3: Test = { a: [true, { x: 7 }, { x: [1, 2, 3] }] };
* ```
*
* you could get the following results with optional-lenses:
* ```ts
* const lensA = getLens<Test>().k('a');
* const a1 = lensA.get(t1); // => undefined (inferred as undefined | string | Array<boolean | { x: number | Array<number>}>)
* const a2 = lensA.get(t2); // => 'Test3' (inferred as undefined | string | Array<boolean | { x: number | Array<number>}>)
* const a3 = lensA.get(t3); // => [true, { x: 7 }, { x: [1, 2, 3] }] (inferred as undefined | string | Array<boolean | { x: number | Array<number>}>)
*
* const lensA2X1 = lensA.k(2).k('x').k(1);
* const n1 = lensA2X1.get(t1); // => undefined (inferred as number | undefined)
* const n2 = lensA2X1.get(t2); // => undefined (inferred as number | undefined)
* const n3 = lensA2X1.get(t3); // => 2 (inferred as number | undefined)
* ```
*/
export const getLens = <T>(): OptionalLens<T, T> => {
const get = (value: T) => value;
return {
get,
k: <K extends ToKeys<T>>(key: K): OptionalLens<T, PickReturn<T, K>> =>
_toLens<T, T, K>(get, key),
};
};
/**
* Get a concrete `OptionalLens<T, P>` from an `OptionalLens<any, any>` (or never, if L is no `OptionalLens<any, any>`)
*/
export type ToLensType<L> = [L] extends [OptionalLens<infer T, infer P>]
? OptionalLens<T, P>
: never;
/**
* Get a concrete `T` from an `OptionalLens<T, any>` (or never, if L is no `OptionalLens<any, any>`)
*/
export type ToLensInputType<L> = [L] extends [OptionalLens<infer T, any>] ? T : never;
/**
* Get a concrete `T` from an `OptionalLens<any, T>` (or never, if L is no `OptionalLens<any, any>`)
*/
export type ToLensOutputType<L> = [L] extends [OptionalLens<any, infer T>] ? T : never;
/**
* Get `T`, if `VL` is an `OptionalLens<T, any>`, else get `OptionalLens<VL, any>`
*/
export type ValueOrLens<VL> = [VL] extends [OptionalLens<any, any>]
? ToLensInputType<VL>
: OptionalLens<VL, any>;
/**
* Get return type of `OptionalLens<T, PX>::get(T)`, if `X` is an `OptionalLens<any, any>`,
* else get the return type of `OptionalLens<T, PY>::get(T)`, if `Y` is an `OptionalLens<any, any>`,
* else never.
*/
export type FromLensReturn<X, Y> = [X] extends [OptionalLens<any, any>]
? ToLensOutputType<X> | undefined
: [Y] extends [OptionalLens<any, any>]
? ToLensOutputType<Y> | undefined
: never;
/**
* Utility function to apply an `OptionalLens<T, P>` to a `T`
*/
export const fromValueAndLens =
<T>(value: T) =>
<L extends OptionalLens<T, any>>(lens: L): ToLensOutputType<L> | undefined =>
lens.get(value);
/**
* Utility function to apply a `T` to an `OptionalLens<T, P>`
*/
export const fromLensAndValue =
<L extends OptionalLens<any, any>>(lens: L) =>
<T extends ToLensInputType<L>>(value: T): ToLensOutputType<L> | undefined =>
lens.get(value);
/**
* If the first argument is an `OptionalLens`, this function behaves like `fromLensAndValue`,
* else it behaves like `fromValueAndLens`
*/
export const fromLens =
<X>(valueOrLens1: X) =>
<Y extends ValueOrLens<X>>(valueOrLens2: Y): FromLensReturn<X, Y> =>
isOptionalLens(valueOrLens1)
? valueOrLens1.get(valueOrLens2)
: (<OptionalLens<X, any>>valueOrLens2).get(valueOrLens1);
/**
* Return type of the toGetter function.
* Like {@link OptionalLens}, a `Getter<T>` can be used for optional chaining on arbitrary union types.
* In contrast to {@link OptionalLens}, the initial `Getter<T>` must be obtained from a value of type `T`.
* You can thus use it as kind of ad-hoc lens for a one-time access. In most cases however,
* using an {@link OptionalLens} is the better choice.
*
* See `toGetter` documentation for example usage.
*/
export type Getter<T> = {
get: () => T;
k: <K extends ToKeys<T>>(key: K) => Getter<PickReturn<T, K>>;
};
/**
* Helper type to infer the concrete value type `T` wrapped by a `Getter<T>`
*/
export type ToGetterValue<T> = T extends Getter<infer V> ? V : never;
const _toGetter = <T>(g: () => T): Getter<T> => ({
get: () => g(),
k: <K extends ToKeys<T>>(key: K): Getter<PickReturn<T, K>> => _toGetter(() => pick(g(), key)),
});
/**
* Wraps the given value of type T in a `Getter<T>`.
* A `Getter<T>` can be used like a one-time ad-hoc version of an {@link OptionalLens}.
* In most cases however, using an {@link OptionalLens} is the better choice.
*
* Given the following type and values:
* ```ts
* type Test =
* | number
* | {
* x: Array<number>;
* a: {
* b: number;
* };
* | {
* a: {
* b: string;
* }
* }
* };
*
* let t1: Test = 42;
* let t2: Test = { x: [1, 2, 3] };
* let t3: Test = { a: { b: 'Test' } };
* ```
*
* you could get the following results with toGetter:
* ```ts
* const b1 = toGetter(t1).k('a').k('b').get(); // => undefined (inferred as number | string | undefined)
* const b2 = toGetter(t2).k('a').k('b').get(); // => undefined (inferred as number | string | undefined)
* const b3 = toGetter(t3).k('a').k('b').get(); // => 'Test' (inferred as number | string | undefined)
* const x1 = toGetter(t1).k('x').k(1).get(); // => undefined (inferred as number | undefined)
* const x2 = toGetter(t2).k('x').k(1).get(); // => 2 (inferred as number | undefined)
* const x3 = toGetter(t3).k('x').k(1).get(); // => undefined (inferred as number | undefined)
* ```
*/
export const toGetter = <T>(value: T): Getter<T> => _toGetter<T>(() => value);

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc