enforce strong typing in update, updateIn, without

This commit is contained in:
Stepan Burguchev
2017-07-09 16:49:49 +03:00
parent 43ffe03a9b
commit 1b91b09021
2 changed files with 27 additions and 18 deletions

View File

@@ -48,12 +48,19 @@ declare namespace SeamlessImmutable {
merge(part: DeepPartial<T>, config?: MergeConfig): T & ImmutableObject<T>;
update(property: string, updaterFunction: (value: any, ...additionalParamters: any[]) => any, ...additionalArguments: any[]): ImmutableObject<T>;
updateIn(propertyPath: Array<string>, updaterFunction: (value: any, ...additionalParamters: any[]) => any, ...additionalArguments: any[]): ImmutableObject<T>;
update<K extends keyof T>(property: K, updaterFunction: (value: T[K], ...additionalParameters: any[]) => any, ...additionalArguments: any[]): T & ImmutableObject<T>;
updateIn<K extends keyof T>
(propertyPath: [ K ], updaterFunction: (value: T[K], ...additionalParameters: any[]) => any, ...additionalArguments: any[]): T & ImmutableObject<T>;
updateIn<K extends keyof T, L extends keyof T[K]>
(propertyPath: [ K, L ], updaterFunction: (value: T[K][L], ...additionalParameters: any[]) => any, ...additionalArguments: any[]): T & ImmutableObject<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[]): T & ImmutableObject<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[]): T & ImmutableObject<T>;
without(property: string): ImmutableObject<any>;
without(...properties: string[]): ImmutableObject<any>;
without(filter: (value: any, key: string) => boolean): ImmutableObject<any>;
without<TTarget>(property: keyof T): TTarget & ImmutableObject<TTarget>;
without<TTarget>(...properties: Array<keyof T>): TTarget & ImmutableObject<TTarget>;
without<TTarget>(filter: (value: T[keyof T], key: keyof T) => boolean): TTarget & ImmutableObject<TTarget>;
}
export interface ImmutableArray<T> {
@@ -63,8 +70,7 @@ declare namespace SeamlessImmutable {
flatMap<TTarget>(mapFunction: (item: T) => Array<TTarget>): TTarget[] & ImmutableArray<TTarget>;
}
// an immutable object is both of Type T (i.e., looks like a normal T) and of type Immutable<T>
export type Immutable<T> = T & (ImmutableObject<T> | ImmutableArray<T>);
export type Immutable<T> = ImmutableObject<T> | ImmutableArray<T>;
export function from<T>(obj: Array<T>, options?: Options): Array<T> & ImmutableArray<T>;
export function from<T>(obj: T, options?: Options): T & ImmutableObject<T>;

View File

@@ -78,23 +78,26 @@ interface ExtendedUser extends User {
});
// set: property name is strongly checked
const updatedUser: Immutable.ImmutableObject<User> = immutableUser.set('firstName', 'Whirlwind');
const updatedUser: User & Immutable.ImmutableObject<User> = immutableUser.set('firstName', 'Whirlwind');
// setIn: property path is strongly checked for up to 4 arguments
const updatedUser2: Immutable.ImmutableObject<ExtendedUser> = immutableUserEx.setIn(['address', 'line1'], 'Small house');
const updatedUser2: ExtendedUser & Immutable.ImmutableObject<ExtendedUser> = immutableUserEx.setIn(['address', 'line1'], 'Small house');
// asMutable
const mutableUser1: User = immutableUser.asMutable();
const mutableUser2: 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: User & Immutable.ImmutableObject<User> = immutableUserEx.merge({ address: { line1: 'Small house' }, firstName: 'Jack' });
const updatedUser: Immutable.ImmutableObject<ExtendedUser> = extUser.update("firstName", (firstName): string =>
firstName + "hehe"
);
const updatedInUser: Immutable.ImmutableObject<ExtendedUser> = extUser.updateIn(["address", "line1"], (line): string =>
line + "new address"
);
const userWithoutAddress: Immutable.ImmutableObject<User> = extUser.without("address");
// update: property name is strongly checked
const updatedUser3: User & Immutable.ImmutableObject<User> = immutableUser.update('firstName', x => x.toLowerCase() + ' Whirlwind');
// updateIn: property path is strongly checked for up to 4 arguments
const updatedUser4: User & Immutable.ImmutableObject<User> = immutableUserEx.updateIn([ 'address', 'line1' ], x => x.toLowerCase() + ' 43');
// without: the return type must be specified explicitly or it will be `any`
const simpleUser1: Immutable.ImmutableObject<any> = immutableUserEx.without('address');
const simpleUser2: User & Immutable.ImmutableObject<User> = immutableUserEx.without<User>('address');
const simpleUser3: Immutable.ImmutableObject<any> = immutableUserEx.without('firstName', 'lastName');
}