From cd29edb442b801cde1ccbaba042d5b62263c1bf7 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 5 Aug 2020 09:13:01 +0100 Subject: [PATCH] Write more typescript defs --- src/components/views/rooms/RoomList.tsx | 1 + .../handlers/AccountSettingsHandler.ts | 2 +- .../handlers/RoomAccountSettingsHandler.ts | 2 +- src/settings/handlers/RoomSettingsHandler.ts | 5 +-- src/utils/objects.ts | 34 +++++++++++-------- 5 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/components/views/rooms/RoomList.tsx b/src/components/views/rooms/RoomList.tsx index 09fdbf0864..90270452fd 100644 --- a/src/components/views/rooms/RoomList.tsx +++ b/src/components/views/rooms/RoomList.tsx @@ -245,6 +245,7 @@ export default class RoomList extends React.PureComponent { if (doUpdate) { // We have to break our reference to the room list store if we want to be able to // diff the object for changes, so do that. + // @ts-ignore - ITagMap is ts-ignored so this will have to be too const newSublists = objectWithOnly(newLists, newListIds); const sublists = objectShallowClone(newSublists, (k, v) => arrayFastClone(v)); diff --git a/src/settings/handlers/AccountSettingsHandler.ts b/src/settings/handlers/AccountSettingsHandler.ts index 53180aeba8..d609fd3231 100644 --- a/src/settings/handlers/AccountSettingsHandler.ts +++ b/src/settings/handlers/AccountSettingsHandler.ts @@ -59,7 +59,7 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa } else if (event.getType() === "im.vector.web.settings") { // Figure out what changed and fire those updates const prevContent = prevEvent ? prevEvent.getContent() : {}; - const changedSettings = objectKeyChanges(prevContent, event.getContent()); + const changedSettings = objectKeyChanges>(prevContent, event.getContent()); for (const settingName of changedSettings) { const val = event.getContent()[settingName]; this.watchers.notifyUpdate(settingName, null, SettingLevel.ACCOUNT, val); diff --git a/src/settings/handlers/RoomAccountSettingsHandler.ts b/src/settings/handlers/RoomAccountSettingsHandler.ts index e3449e76c3..53e29653f8 100644 --- a/src/settings/handlers/RoomAccountSettingsHandler.ts +++ b/src/settings/handlers/RoomAccountSettingsHandler.ts @@ -59,7 +59,7 @@ export default class RoomAccountSettingsHandler extends MatrixClientBackedSettin } else if (event.getType() === "im.vector.web.settings") { // Figure out what changed and fire those updates const prevContent = prevEvent ? prevEvent.getContent() : {}; - const changedSettings = objectKeyChanges(prevContent, event.getContent()); + const changedSettings = objectKeyChanges>(prevContent, event.getContent()); for (const settingName of changedSettings) { const val = event.getContent()[settingName]; this.watchers.notifyUpdate(settingName, roomId, SettingLevel.ROOM_ACCOUNT, val); diff --git a/src/settings/handlers/RoomSettingsHandler.ts b/src/settings/handlers/RoomSettingsHandler.ts index 4b4d4c4ad9..3315e40a65 100644 --- a/src/settings/handlers/RoomSettingsHandler.ts +++ b/src/settings/handlers/RoomSettingsHandler.ts @@ -65,9 +65,10 @@ export default class RoomSettingsHandler extends MatrixClientBackedSettingsHandl } else if (event.getType() === "im.vector.web.settings") { // Figure out what changed and fire those updates const prevContent = prevEvent ? prevEvent.getContent() : {}; - const changedSettings = objectKeyChanges(prevContent, event.getContent()); + const changedSettings = objectKeyChanges>(prevContent, event.getContent()); for (const settingName of changedSettings) { - this.watchers.notifyUpdate(settingName, roomId, SettingLevel.ROOM, event.getContent()[settingName]); + this.watchers.notifyUpdate(settingName, roomId, SettingLevel.ROOM, + event.getContent()[settingName]); } } }; diff --git a/src/utils/objects.ts b/src/utils/objects.ts index ddd9830832..658491188d 100644 --- a/src/utils/objects.ts +++ b/src/utils/objects.ts @@ -16,15 +16,17 @@ limitations under the License. import { arrayDiff, arrayHasDiff, arrayMerge, arrayUnion } from "./arrays"; +type ObjectExcluding = {[k in Exclude]: O[k]}; + /** * Gets a new object which represents the provided object, excluding some properties. * @param a The object to strip properties of. Must be defined. * @param props The property names to remove. * @returns The new object without the provided properties. */ -export function objectExcluding(a: any, props: string[]): any { +export function objectExcluding(a: O, props: P): ObjectExcluding { // We use a Map to avoid hammering the `delete` keyword, which is slow and painful. - const tempMap = new Map(Object.entries(a)); + const tempMap = new Map(Object.entries(a) as [keyof O, any][]); for (const prop of props) { tempMap.delete(prop); } @@ -33,7 +35,7 @@ export function objectExcluding(a: any, props: string[]): any { return Array.from(tempMap.entries()).reduce((c, [k, v]) => { c[k] = v; return c; - }, {}); + }, {} as O); } /** @@ -43,13 +45,13 @@ export function objectExcluding(a: any, props: string[]): any { * @param props The property names to keep. * @returns The new object with only the provided properties. */ -export function objectWithOnly(a: any, props: string[]): any { - const existingProps = Object.keys(a); +export function objectWithOnly(a: O, props: P): {[k in P[number]]: O[k]} { + const existingProps = Object.keys(a) as (keyof O)[]; const diff = arrayDiff(existingProps, props); if (diff.removed.length === 0) { return objectShallowClone(a); } else { - return objectExcluding(a, diff.removed); + return objectExcluding(a, diff.removed) as {[k in P[number]]: O[k]}; } } @@ -64,9 +66,9 @@ export function objectWithOnly(a: any, props: string[]): any { * First argument is the property key with the second being the current value. * @returns A cloned object. */ -export function objectShallowClone(a: any, propertyCloner?: (k: string, v: any) => any): any { - const newObj = {}; - for (const [k, v] of Object.entries(a)) { +export function objectShallowClone(a: O, propertyCloner?: (k: keyof O, v: O[keyof O]) => any): O { + const newObj = {} as O; + for (const [k, v] of Object.entries(a) as [keyof O, O[keyof O]][]) { newObj[k] = v; if (propertyCloner) { newObj[k] = propertyCloner(k, v); @@ -83,7 +85,7 @@ export function objectShallowClone(a: any, propertyCloner?: (k: string, v: any) * @param b The second object. Must be defined. * @returns True if there's a difference between the objects, false otherwise */ -export function objectHasDiff(a: any, b: any): boolean { +export function objectHasDiff(a: O, b: O): boolean { const aKeys = Object.keys(a); const bKeys = Object.keys(b); if (arrayHasDiff(aKeys, bKeys)) return true; @@ -92,6 +94,8 @@ export function objectHasDiff(a: any, b: any): boolean { return possibleChanges.some(k => a[k] !== b[k]); } +type Diff = { changed: K[], added: K[], removed: K[] }; + /** * Determines the keys added, changed, and removed between two objects. * For changes, simple triple equal comparisons are done, not in-depth @@ -100,9 +104,9 @@ export function objectHasDiff(a: any, b: any): boolean { * @param b The second object. Must be defined. * @returns The difference between the keys of each object. */ -export function objectDiff(a: any, b: any): { changed: string[], added: string[], removed: string[] } { - const aKeys = Object.keys(a); - const bKeys = Object.keys(b); +export function objectDiff(a: O, b: O): Diff { + const aKeys = Object.keys(a) as (keyof O)[]; + const bKeys = Object.keys(b) as (keyof O)[]; const keyDiff = arrayDiff(aKeys, bKeys); const possibleChanges = arrayUnion(aKeys, bKeys); const changes = possibleChanges.filter(k => a[k] !== b[k]); @@ -119,7 +123,7 @@ export function objectDiff(a: any, b: any): { changed: string[], added: string[] * @returns The keys which have been added, removed, or changed between the * two objects. */ -export function objectKeyChanges(a: any, b: any): string[] { +export function objectKeyChanges(a: O, b: O): (keyof O)[] { const diff = objectDiff(a, b); return arrayMerge(diff.removed, diff.added, diff.changed); } @@ -131,6 +135,6 @@ export function objectKeyChanges(a: any, b: any): string[] { * @param obj The object to clone. * @returns The cloned object */ -export function objectClone(obj: any): any { +export function objectClone(obj: O): O { return JSON.parse(JSON.stringify(obj)); }