mirror of
https://github.com/gosticks/DefinitelyTyped.git
synced 2026-08-12 04:50:18 +00:00
Refactor: conditional type for object/array/primitive, and deep immutable interface for nested objects (#29699)
This commit is contained in:
committed by
Sheetal Nandi
parent
049be10668
commit
f962dce1d2
Vendored
+35
-34
@@ -3,8 +3,9 @@
|
||||
// Definitions by: alex3165 <https://github.com/alex3165>
|
||||
// Stepan Burguchev <https://github.com/xsburg>
|
||||
// Geir Sagberg <https://github.com/geirsagberg>
|
||||
// Richard Honor <https://github.com/RMHonor>
|
||||
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
||||
// TypeScript Version: 2.4
|
||||
// TypeScript Version: 2.8
|
||||
|
||||
export = SeamlessImmutable;
|
||||
|
||||
@@ -31,17 +32,17 @@ declare namespace SeamlessImmutable {
|
||||
}
|
||||
|
||||
interface ImmutableObjectMixin<T> {
|
||||
set<K extends keyof T>(property: K, value: T[K]): ImmutableObject<T>;
|
||||
set<TValue>(property: string, value: TValue): ImmutableObject<T>;
|
||||
set<K extends keyof T>(property: K, value: T[K]): Immutable<T>;
|
||||
set<TValue>(property: string, value: TValue): Immutable<T>;
|
||||
|
||||
setIn<K extends keyof T>(propertyPath: [ K ], value: T[K]): ImmutableObject<T>;
|
||||
setIn<K extends keyof T, L extends keyof T[K]>(propertyPath: [ K, L ], value: T[K][L]): ImmutableObject<T>;
|
||||
setIn<K extends keyof T, L extends keyof T[K], M extends keyof T[K][L]>(propertyPath: [ K, L, M ], value: T[K][L][M]): ImmutableObject<T>;
|
||||
setIn<K extends keyof T>(propertyPath: [ K ], value: T[K]): Immutable<T>;
|
||||
setIn<K extends keyof T, L extends keyof T[K]>(propertyPath: [ K, L ], value: T[K][L]): Immutable<T>;
|
||||
setIn<K extends keyof T, L extends keyof T[K], M extends keyof T[K][L]>(propertyPath: [ K, L, M ], value: T[K][L][M]): Immutable<T>;
|
||||
setIn<K extends keyof T, L extends keyof T[K], M extends keyof T[K][L], N extends keyof T[K][L][M]>(
|
||||
propertyPath: [ K, L, M, N ], value: T[K][L][M][N]): ImmutableObject<T>;
|
||||
propertyPath: [ K, L, M, N ], value: T[K][L][M][N]): Immutable<T>;
|
||||
setIn<K extends keyof T, L extends keyof T[K], M extends keyof T[K][L], N extends keyof T[K][L][M], O extends keyof T[K][L][M][N]>(
|
||||
propertyPath: [ K, L, M, N, O ], value: T[K][L][M][N][O]): ImmutableObject<T>;
|
||||
setIn<TValue>(propertyPath: string[], value: TValue): ImmutableObject<T>;
|
||||
propertyPath: [ K, L, M, N, O ], value: T[K][L][M][N][O]): Immutable<T>;
|
||||
setIn<TValue>(propertyPath: string[], value: TValue): Immutable<T>;
|
||||
|
||||
getIn<K extends keyof T>(propertyPath: [ K ]): Immutable<T[K]>;
|
||||
getIn<K extends keyof T>(propertyPath: [ K ], defaultValue: T[K]): Immutable<T[K]>;
|
||||
@@ -59,48 +60,48 @@ declare namespace SeamlessImmutable {
|
||||
|
||||
asMutable(opts?: AsMutableOptions): T;
|
||||
|
||||
merge(part: DeepPartial<T>, config?: MergeConfig): ImmutableObject<T>;
|
||||
merge(part: DeepPartial<T>, config?: MergeConfig): Immutable<T>;
|
||||
|
||||
update<K extends keyof T>(property: K, updaterFunction: (value: T[K], ...additionalParameters: any[]) => any, ...additionalArguments: any[]): ImmutableObject<T>;
|
||||
update<TValue>(property: string, updaterFunction: (value: TValue, ...additionalParameters: any[]) => any, ...additionalArguments: any[]): ImmutableObject<T>;
|
||||
update<K extends keyof T>(property: K, updaterFunction: (value: T[K], ...additionalParameters: any[]) => any, ...additionalArguments: any[]): Immutable<T>;
|
||||
update<TValue>(property: string, updaterFunction: (value: TValue, ...additionalParameters: any[]) => any, ...additionalArguments: any[]): Immutable<T>;
|
||||
|
||||
updateIn<K extends keyof T>(
|
||||
propertyPath: [ K ], updaterFunction: (value: T[K], ...additionalParameters: any[]) => any, ...additionalArguments: any[]): ImmutableObject<T>;
|
||||
propertyPath: [ K ], updaterFunction: (value: T[K], ...additionalParameters: any[]) => any, ...additionalArguments: any[]): Immutable<T>;
|
||||
updateIn<K extends keyof T, L extends keyof T[K]>(
|
||||
propertyPath: [ K, L ], updaterFunction: (value: T[K][L], ...additionalParameters: any[]) => any, ...additionalArguments: any[]): ImmutableObject<T>;
|
||||
propertyPath: [ K, L ], updaterFunction: (value: T[K][L], ...additionalParameters: any[]) => any, ...additionalArguments: any[]): Immutable<T>;
|
||||
updateIn<K extends keyof T, L extends keyof T[K], M extends keyof T[K][L]>(
|
||||
propertyPath: [ K, L, M ], updaterFunction: (value: T[K][L][M], ...additionalParameters: any[]) => any, ...additionalArguments: any[]): ImmutableObject<T>;
|
||||
propertyPath: [ K, L, M ], updaterFunction: (value: T[K][L][M], ...additionalParameters: any[]) => any, ...additionalArguments: any[]): Immutable<T>;
|
||||
updateIn<K extends keyof T, L extends keyof T[K], M extends keyof T[K][L], N extends keyof T[K][L][M]>(
|
||||
propertyPath: [ K, L, M, N ], updaterFunction: (value: T[K][L][M][N], ...additionalParameters: any[]) => any, ...additionalArguments: any[]): ImmutableObject<T>;
|
||||
propertyPath: [ K, L, M, N ], updaterFunction: (value: T[K][L][M][N], ...additionalParameters: any[]) => any, ...additionalArguments: any[]): Immutable<T>;
|
||||
updateIn<K extends keyof T, L extends keyof T[K], M extends keyof T[K][L], N extends keyof T[K][L][M], O extends keyof T[K][L][M][N]>(
|
||||
propertyPath: [ K, L, M, N, O ], updaterFunction: (value: T[K][L][M][N][O], ...additionalParameters: any[]) => any, ...additionalArguments: any[]): ImmutableObject<T>;
|
||||
updateIn<TValue>(propertyPath: string[], updaterFunction: (value: TValue, ...additionalParameters: any[]) => any, ...additionalArguments: any[]): ImmutableObject<T>;
|
||||
propertyPath: [ K, L, M, N, O ], updaterFunction: (value: T[K][L][M][N][O], ...additionalParameters: any[]) => any, ...additionalArguments: any[]): Immutable<T>;
|
||||
updateIn<TValue>(propertyPath: string[], updaterFunction: (value: TValue, ...additionalParameters: any[]) => any, ...additionalArguments: any[]): Immutable<T>;
|
||||
|
||||
without<K extends keyof T>(property: K): ImmutableObject<T>;
|
||||
without<K extends keyof T>(...properties: K[]): ImmutableObject<T>;
|
||||
without<K extends keyof T>(filter: (value: T[K], key: K) => boolean): ImmutableObject<T>;
|
||||
without<K extends keyof T>(property: K): Immutable<T>;
|
||||
without<K extends keyof T>(...properties: K[]): Immutable<T>;
|
||||
without<K extends keyof T>(filter: (value: T[K], key: K) => boolean): Immutable<T>;
|
||||
|
||||
replace<S>(valueObj: S, options?: ReplaceConfig): ImmutableObject<S>;
|
||||
replace<S>(valueObj: S, options?: ReplaceConfig): Immutable<S>;
|
||||
}
|
||||
|
||||
interface ImmutableArrayMixin<T> {
|
||||
asMutable(opts?: AsMutableOptions): T[];
|
||||
asObject(toKeyValue: (item: T) => [string, any]): ImmutableObject<any>;
|
||||
flatMap<TTarget>(mapFunction: (item: T) => TTarget[]): ImmutableArray<TTarget>;
|
||||
interface ImmutableArrayMixin<T extends Array<T[0]>> {
|
||||
asMutable(opts?: AsMutableOptions): T;
|
||||
asObject(toKeyValue: (item: T[0]) => [string, any]): Immutable<object>;
|
||||
flatMap<TTarget>(mapFunction: (item: T[0]) => TTarget): Immutable<TTarget extends any[] ? TTarget : TTarget[]>;
|
||||
}
|
||||
|
||||
type ImmutableObject<T> = T & ImmutableObjectMixin<T>;
|
||||
type ImmutableArray<T> = T[] & ImmutableArrayMixin<T>;
|
||||
type Immutable<T> = ImmutableObject<T> | ImmutableArray<T>;
|
||||
type BaseImmutable<T> = (T extends any[] ? ImmutableArrayMixin<T> : ImmutableObjectMixin<T>) & T;
|
||||
|
||||
function from<T>(obj: T[], options?: Options): ImmutableArray<T>;
|
||||
function from<T>(obj: T, options?: Options): ImmutableObject<T>;
|
||||
type Immutable<T> = {
|
||||
readonly [P in keyof T]: T[P] extends object ? Immutable<T[P]> : T[P]
|
||||
} & BaseImmutable<T>;
|
||||
|
||||
function from<T>(obj: T, options?: Options): Immutable<T>;
|
||||
|
||||
function isImmutable(target: any): boolean;
|
||||
function ImmutableError(message: string): Error;
|
||||
|
||||
function replace<T, S>(obj: ImmutableObject<T>, valueObj: S, options?: ReplaceConfig): ImmutableObject<S>;
|
||||
function replace<T, S>(obj: Immutable<T>, valueObj: S, options?: ReplaceConfig): Immutable<S>;
|
||||
}
|
||||
|
||||
declare function SeamlessImmutable<T>(obj: T[], options?: SeamlessImmutable.Options): SeamlessImmutable.ImmutableArray<T>;
|
||||
declare function SeamlessImmutable<T>(obj: T, options?: SeamlessImmutable.Options): SeamlessImmutable.ImmutableObject<T>;
|
||||
declare function SeamlessImmutable<T>(obj: T, options?: SeamlessImmutable.Options): SeamlessImmutable.Immutable<T>;
|
||||
|
||||
@@ -25,13 +25,13 @@ interface ExtendedUser extends User {
|
||||
lastName: string;
|
||||
}
|
||||
|
||||
const arrayOfNumbers1: Immutable.ImmutableArray<number> = Immutable.from([0, 2]);
|
||||
const arrayOfNumbers2: Immutable.ImmutableArray<number> = Immutable([0, 2]);
|
||||
const user1: Immutable.ImmutableObject<User> = Immutable.from({
|
||||
const arrayOfNumbers1: Immutable.Immutable<number[]> = Immutable.from([0, 2]);
|
||||
const arrayOfNumbers2: Immutable.Immutable<number[]> = Immutable([0, 2]);
|
||||
const user1: Immutable.Immutable<User> = Immutable.from({
|
||||
firstName: 'Angry',
|
||||
lastName: 'Monkey'
|
||||
});
|
||||
const user2: Immutable.ImmutableObject<User> = Immutable({
|
||||
const user2: Immutable.Immutable<User> = Immutable({
|
||||
firstName: 'Angry',
|
||||
lastName: 'Monkey'
|
||||
});
|
||||
@@ -44,7 +44,7 @@ interface ExtendedUser extends User {
|
||||
|
||||
{
|
||||
const isImmutable: boolean = Immutable.isImmutable(Immutable.from([0, 2]));
|
||||
const user1: Immutable.ImmutableObject<User> = Immutable.from({
|
||||
const user1: Immutable.Immutable<User> = Immutable.from({
|
||||
firstName: 'Angry',
|
||||
lastName: 'Monkey'
|
||||
});
|
||||
@@ -56,19 +56,23 @@ interface ExtendedUser extends User {
|
||||
// Instance syntax: immutable array
|
||||
// ---------------------------------------------------------------
|
||||
{
|
||||
const array: Immutable.ImmutableArray<User> = Immutable.from<User>([ { firstName: 'Angry', lastName: 'Monkey' } ]);
|
||||
const array: Immutable.Immutable<User[]> = Immutable.from([ { firstName: 'Angry', lastName: 'Monkey' } ]);
|
||||
|
||||
// asMutable
|
||||
const mutableArray1: User[] = array.asMutable();
|
||||
const mutableArray2: User[] = array.asMutable({ deep: true });
|
||||
|
||||
// flatMap
|
||||
const flatMappedArray: Immutable.ImmutableArray<User> = array.flatMap((value: User) =>
|
||||
const flatMappedArray: Immutable.Immutable<User[]> = array.flatMap((value: User) =>
|
||||
[value, value]
|
||||
);
|
||||
|
||||
const flatMappedArrayStrings: Immutable.Immutable<string[]> = array.flatMap((value: User) =>
|
||||
value.firstName
|
||||
);
|
||||
|
||||
// asObject
|
||||
const arrayToObject1: Immutable.ImmutableObject<any> = array.asObject((value) => [value.toString(), value]);
|
||||
const arrayToObject1: Immutable.Immutable<object> = array.asObject((value) => [value.toString(), value]);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -76,11 +80,11 @@ interface ExtendedUser extends User {
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
{
|
||||
const immutableUser: Immutable.ImmutableObject<User> = Immutable.from({
|
||||
const immutableUser: Immutable.Immutable<User> = Immutable.from({
|
||||
firstName: 'Pure',
|
||||
lastName: 'Gold'
|
||||
});
|
||||
const immutableUserEx: Immutable.ImmutableObject<ExtendedUser> = Immutable.from({
|
||||
const immutableUserEx: Immutable.Immutable<ExtendedUser> = Immutable.from({
|
||||
firstName: 'Hairy',
|
||||
lastName: 'Dog',
|
||||
address: {
|
||||
@@ -94,37 +98,37 @@ interface ExtendedUser extends User {
|
||||
};
|
||||
|
||||
// set: property name is strongly checked
|
||||
const updatedUser01: Immutable.ImmutableObject<User> = immutableUser.set('firstName', 'Whirlwind');
|
||||
const updatedUser02: Immutable.ImmutableObject<User> = immutableUser.set(data.propertyId, 'Whirlwind');
|
||||
const updatedUser01: Immutable.Immutable<User> = immutableUser.set('firstName', 'Whirlwind');
|
||||
const updatedUser02: Immutable.Immutable<User> = immutableUser.set(data.propertyId, 'Whirlwind');
|
||||
|
||||
// setIn: property path is strongly checked for up to 5 arguments (helps with refactoring and intellisense)
|
||||
// but will fall back to any[] if there are dynamic arguments on the way
|
||||
const updatedUser11: Immutable.ImmutableObject<ExtendedUser> = immutableUserEx.setIn(['address', 'line1'], 'Small house');
|
||||
const updatedUser12: Immutable.ImmutableObject<ExtendedUser> = immutableUserEx.setIn([ data.propertyId, 'line1' ], 'Small house');
|
||||
const updatedUser11: Immutable.Immutable<ExtendedUser> = immutableUserEx.setIn(['address', 'line1'], 'Small house');
|
||||
const updatedUser12: Immutable.Immutable<ExtendedUser> = immutableUserEx.setIn([ data.propertyId, 'line1' ], 'Small house');
|
||||
|
||||
// asMutable
|
||||
const mutableUser21: User = immutableUser.asMutable();
|
||||
const mutableUser22: User = immutableUser.asMutable({ deep: true });
|
||||
|
||||
// merge: merged part is strongly checked as a deeply partial object
|
||||
const mergedUser: Immutable.ImmutableObject<User> = immutableUserEx.merge({ address: { line1: 'Small house' }, firstName: 'Jack' });
|
||||
const mergedUser: Immutable.Immutable<User> = immutableUserEx.merge({ address: { line1: 'Small house' }, firstName: 'Jack' });
|
||||
|
||||
// update: property name is strongly checked
|
||||
const updatedUser41: Immutable.ImmutableObject<User> = immutableUser.update('firstName', x => x.toLowerCase() + ' Whirlwind');
|
||||
const updatedUser41: Immutable.Immutable<User> = immutableUser.update('firstName', x => x.toLowerCase() + ' Whirlwind');
|
||||
// the type of the updated value must be explicity specified in case of fallback
|
||||
const updatedUser42: Immutable.ImmutableObject<User> = immutableUser.update<string>(data.propertyId, x => x.toLowerCase() + ' Whirlwind');
|
||||
const updatedUser42: Immutable.Immutable<User> = immutableUser.update<string>(data.propertyId, x => x.toLowerCase() + ' Whirlwind');
|
||||
|
||||
// updateIn: property path is strongly checked for up to 5 arguments (helps with refactoring and intellisense)
|
||||
// but will fall back to any[] if there are dynamic arguments on the way
|
||||
const updatedUser51: Immutable.ImmutableObject<User> = immutableUserEx.updateIn([ 'address', 'line1' ], x => x.toLowerCase() + ' 43');
|
||||
const updatedUser51: Immutable.Immutable<User> = immutableUserEx.updateIn([ 'address', 'line1' ], x => x.toLowerCase() + ' 43');
|
||||
// the type of the updated value must be explicity specified in case of fallback
|
||||
const updatedUser52: Immutable.ImmutableObject<User> = immutableUserEx.updateIn<string>([ data.propertyId, 'line1' ], x => x.toLowerCase() + ' 43');
|
||||
const updatedUser52: Immutable.Immutable<User> = immutableUserEx.updateIn<string>([ data.propertyId, 'line1' ], x => x.toLowerCase() + ' 43');
|
||||
|
||||
// without
|
||||
const simpleUser1: Immutable.ImmutableObject<User> = immutableUserEx.without('address');
|
||||
const simpleUser1: Immutable.Immutable<User> = immutableUserEx.without('address');
|
||||
|
||||
// getIn: propertyPath is strongly typed up to 5 parameters
|
||||
const firstNameWithoutDefault = immutableUser.getIn(['firstName']); // infers Immutable<string>
|
||||
const firstNameWithoutDefault: string = immutableUser.getIn(['firstName']); // infers Immutable<string>
|
||||
const firstNameWithDefault = immutableUser.getIn(['firstName'], ''); // infers Immutable<string>
|
||||
const firstNameWithDynamicPathWithoutDefault = immutableUser.getIn(['first' + 'name']);
|
||||
const firstNameWithDynamicPathWithDefault = immutableUser.getIn(['first' + 'name'], '');
|
||||
|
||||
Reference in New Issue
Block a user