mirror of
https://github.com/FlipsideCrypto/DefinitelyTyped.git
synced 2026-02-06 10:56:53 +00:00
Add mergerino type definitions (#37712)
This commit is contained in:
parent
99bff85ef4
commit
21a2f12b2b
87
types/mergerino/index.d.ts
vendored
Normal file
87
types/mergerino/index.d.ts
vendored
Normal file
@ -0,0 +1,87 @@
|
||||
// Type definitions for mergerino 0.4
|
||||
// Project: https://github.com/fuzetsu/mergerino#readme
|
||||
// Definitions by: Slawomir "Fivitti" Figiel <https://github.com/fivitti>
|
||||
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
||||
// TypeScript Version: 3.4
|
||||
|
||||
// TypeScript in version below 3.4 doesn't correctly support FunctionPatch. Arguments have "any" type.
|
||||
|
||||
/**
|
||||
* Nice side effect of flattening array arguments is that you can easily
|
||||
* add conditions to your patches using nested arrays.
|
||||
*
|
||||
* Arrays may be nested in any depth.
|
||||
*/
|
||||
export interface DeepArray<T> extends ReadonlyArray<T | DeepArray<T>> { }
|
||||
|
||||
/**
|
||||
* If you want to fully remove a property from an object specify undefined as the value.
|
||||
*/
|
||||
export type DeletePatch = undefined;
|
||||
|
||||
/**
|
||||
* If you want to replace a property based on its current value, use a function.
|
||||
*
|
||||
* If you pass a function it will receive the current value as the first argument
|
||||
* and the merge function as the second. The return value will be the replacement.
|
||||
* The value you return will bypass merging logic and simply overwrite the property.
|
||||
*/
|
||||
export type FunctionPatch<T> = (val: T, merge: Merge<T extends object ? T : never>) => T;
|
||||
|
||||
/**
|
||||
* If you want to replace a array specify new array as the value.
|
||||
*
|
||||
* If you want edit array's item or insert new item specify object as the value.
|
||||
* Keys of this object are array's indexes, values are patches of array's items.
|
||||
*/
|
||||
export type ArrayPatch<T> = T extends Array<infer V> ? ObjectPatch<Record<number, V>> : never;
|
||||
|
||||
/**
|
||||
* Mergerino merges immutably meaning that the target object will never be mutated (changed).
|
||||
* Instead each object along the path your patch specifies will be shallow copied into a new object.
|
||||
*/
|
||||
export type NestedPatch<T> = T extends object ? ObjectPatch<T> : never;
|
||||
|
||||
/**
|
||||
* 1. Each object along the path your patch specifies will be shallow copied into a new object.
|
||||
* 2. Specify undefined as the value fully remove a property from an object.
|
||||
* 3. Use a function if you want to replace a property based on its current value.
|
||||
*/
|
||||
export type ObjectPatch<S extends object> = { [K in keyof S]?: S[K] | DeletePatch | FunctionPatch<S[K]> | NestedPatch<S[K]> | ArrayPatch<S[K]> };
|
||||
|
||||
/**
|
||||
* Falsy patches are ignored
|
||||
*/
|
||||
export type Falsy = false | 0 | '' | null | undefined;
|
||||
|
||||
/**
|
||||
* Passing a function as a top level patch acts exactly the same as a function
|
||||
* passed to a specific property. It receives the full state object as the first
|
||||
* argument, the merge function as the second.
|
||||
*/
|
||||
export type TopLevelPatch<S extends object> = FunctionPatch<S> | ObjectPatch<S> | ArrayPatch<S> | Falsy;
|
||||
|
||||
/**
|
||||
* You can pass multiple patches in a single merge call, array arguments will
|
||||
* be flattened before processing.
|
||||
*/
|
||||
export type MultipleTopLevelPatch<S extends object> = TopLevelPatch<S> | DeepArray<TopLevelPatch<S>>;
|
||||
|
||||
/**
|
||||
* Main Mergerino function. An immutable merge util for state management.
|
||||
*
|
||||
* You can pass multiple patches in a single merge call, array arguments will be flattened before processing.
|
||||
* Since falsy patches are ignored.
|
||||
*/
|
||||
export type Merge<S extends object> = (source: S, ...patches: Array<MultipleTopLevelPatch<S>>) => S;
|
||||
|
||||
/**
|
||||
* Main Mergerino function. An immutable merge util for state management.
|
||||
*
|
||||
* You can pass multiple patches in a single merge call, array arguments will be flattened before processing.
|
||||
* Since falsy patches are ignored.
|
||||
*/
|
||||
// tslint:disable-next-line:npm-naming
|
||||
export default function merge<S extends object>(source: S, ...patches: Array<MultipleTopLevelPatch<S>>): S;
|
||||
// Mergerino uses "default export", but no in minified version which is checked by dtslint.
|
||||
// This line supress error: The types for mergerino specify 'export default' but the source does not mention 'default' anywhere.
|
||||
216
types/mergerino/mergerino-tests.ts
Normal file
216
types/mergerino/mergerino-tests.ts
Normal file
@ -0,0 +1,216 @@
|
||||
import merge from 'mergerino';
|
||||
|
||||
function deletingWorks() {
|
||||
interface State {
|
||||
deep: {
|
||||
prop?: string;
|
||||
};
|
||||
fake?: any;
|
||||
other: boolean | null;
|
||||
prop: boolean;
|
||||
}
|
||||
|
||||
const state: State = {
|
||||
prop: true,
|
||||
other: true,
|
||||
deep: { prop: 'foo' },
|
||||
};
|
||||
|
||||
const newState = merge(state, {
|
||||
deep: { prop: undefined },
|
||||
fake: undefined, // deleting non existent key
|
||||
other: null,
|
||||
prop: undefined,
|
||||
});
|
||||
}
|
||||
|
||||
function functionSubWorks() {
|
||||
interface State {
|
||||
age: number;
|
||||
name: string;
|
||||
obj: {
|
||||
prop?: boolean;
|
||||
replaced?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
const state: State = {
|
||||
age: 10,
|
||||
name: 'bob',
|
||||
obj: { prop: true }
|
||||
};
|
||||
|
||||
const newState = merge(state, {
|
||||
age: x => x * 10,
|
||||
name: (x, m) => {
|
||||
return x;
|
||||
},
|
||||
obj: () => ({ replaced: true }),
|
||||
});
|
||||
}
|
||||
|
||||
function deepFunctionSubToUncreatedObjectPath() {
|
||||
interface State {
|
||||
add?: {
|
||||
stats: {
|
||||
count: number;
|
||||
};
|
||||
};
|
||||
orig: boolean;
|
||||
}
|
||||
|
||||
const state: State = {
|
||||
orig: true
|
||||
};
|
||||
|
||||
const newState = merge(
|
||||
state,
|
||||
{
|
||||
add: {
|
||||
stats: {
|
||||
count: x => x + 1
|
||||
},
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function addNestedObject() {
|
||||
interface State {
|
||||
age: number;
|
||||
add?: {
|
||||
sub: boolean;
|
||||
};
|
||||
}
|
||||
const state: State = { age: 10 };
|
||||
const add = { sub: true };
|
||||
const newState = merge(state, { add });
|
||||
}
|
||||
|
||||
function deepMergeObjects() {
|
||||
interface State {
|
||||
age: number;
|
||||
sub: {
|
||||
sub: {
|
||||
prop: boolean;
|
||||
newProp?: boolean;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const state: State = {
|
||||
age: 10, sub: {
|
||||
sub: { prop: true },
|
||||
},
|
||||
};
|
||||
|
||||
const newState = merge(
|
||||
state,
|
||||
{
|
||||
sub: {
|
||||
sub:
|
||||
{
|
||||
newProp: true,
|
||||
}
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function functionPatch() {
|
||||
interface State {
|
||||
age: number;
|
||||
foo: string;
|
||||
prop?: boolean;
|
||||
}
|
||||
const state: State = { age: 10, foo: 'bar' };
|
||||
const newState = merge(state, (s, m) => {
|
||||
return merge(s, { prop: true });
|
||||
});
|
||||
}
|
||||
|
||||
function multiArrayFalsyPatches() {
|
||||
interface State {
|
||||
age?: number;
|
||||
foo: string;
|
||||
baz?: number;
|
||||
hello?: boolean;
|
||||
arr?: number[];
|
||||
prop?: boolean;
|
||||
}
|
||||
const state: State = { foo: 'bar' };
|
||||
const newState = merge(
|
||||
state,
|
||||
{ baz: 5 },
|
||||
{ hello: false },
|
||||
[{ arr: [1, 2, 3] }, [[{ prop: true }]], false, null],
|
||||
undefined,
|
||||
'',
|
||||
0,
|
||||
null,
|
||||
(s, m) => m(s, { age: 10 }),
|
||||
[[[[[[[{ age: (x: number) => x * 3 }]]]]]]],
|
||||
);
|
||||
}
|
||||
|
||||
function arrayPatches() {
|
||||
const arr = [1, 2, 3];
|
||||
const newArr = merge(arr, { 2: 100 }, { 0: undefined }, { 0: 200 });
|
||||
}
|
||||
|
||||
function deepMergeWithArr() {
|
||||
interface State {
|
||||
foo: string;
|
||||
deep: {
|
||||
arr: number[];
|
||||
prop: boolean;
|
||||
};
|
||||
}
|
||||
const state: State = { foo: 'bar', deep: { arr: [1, 2, 3], prop: false } };
|
||||
const newState = merge(state, { deep: { arr: { 1: 20 } } });
|
||||
}
|
||||
|
||||
// ToDo: It shoudn't be allowed, but it occurs when I use "infer" to get array type
|
||||
function arrayObjectPatchNonExisitngProperty() {
|
||||
interface State {
|
||||
arr: Array<{
|
||||
prop: boolean;
|
||||
}>;
|
||||
}
|
||||
const state: State = { arr: [{ prop: true }] };
|
||||
const newState = merge(state, { arr: { 0: { prop: false, nonExists: 42 } } });
|
||||
}
|
||||
|
||||
function topLevelFunctionPatch() {
|
||||
type State =
|
||||
| {
|
||||
age: number;
|
||||
foo: string;
|
||||
}
|
||||
| { replaced: boolean };
|
||||
const state = { age: 20, foo: 'bar' };
|
||||
const replacement = { replaced: true };
|
||||
const newState = merge<State>(state, () => replacement);
|
||||
}
|
||||
|
||||
function reuseObjectIfSameRefWhenPatching() {
|
||||
const state = { deep: { prop: true } };
|
||||
const newState = merge(state, { deep: state.deep });
|
||||
}
|
||||
|
||||
function replacePrimitiveWithObjectAndViceVersa() {
|
||||
interface State {
|
||||
count:
|
||||
| number
|
||||
| {
|
||||
prop: boolean;
|
||||
};
|
||||
foo:
|
||||
| number
|
||||
| {
|
||||
prop: boolean;
|
||||
};
|
||||
}
|
||||
const state: State = { count: 10, foo: { prop: true } };
|
||||
const newState = merge(state, { count: { prop: true }, foo: 10 });
|
||||
}
|
||||
23
types/mergerino/tsconfig.json
Normal file
23
types/mergerino/tsconfig.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"lib": [
|
||||
"es6"
|
||||
],
|
||||
"noImplicitAny": true,
|
||||
"noImplicitThis": true,
|
||||
"strictFunctionTypes": true,
|
||||
"strictNullChecks": true,
|
||||
"baseUrl": "../",
|
||||
"typeRoots": [
|
||||
"../"
|
||||
],
|
||||
"types": [],
|
||||
"noEmit": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
},
|
||||
"files": [
|
||||
"index.d.ts",
|
||||
"mergerino-tests.ts"
|
||||
]
|
||||
}
|
||||
3
types/mergerino/tslint.json
Normal file
3
types/mergerino/tslint.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "dtslint/dt.json"
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user