From 08b03ace60f1ea411f98b82622dbf67b23a1cee3 Mon Sep 17 00:00:00 2001 From: Severiano Badajoz Date: Tue, 17 Aug 2021 17:15:53 -0700 Subject: [PATCH] chore: type general utils (#2381) * type camera * type reducer store * type actionhelpers * type catchErrorsWrap callsite * missed camera member var * type nameCreators * type makeContinousDimensionName callsite * type promise limit * type quantile * type range * introduce TypedArray + NumericArray * type range * cleanup test * fix call sites * type plimit call site * finish typing camera * use our TypedArray * type scientific and sigFig utils and callsites * simple typings * type catLabelSort * type callsite * type * callsites * type camera methods * swap back to strings, set defaults accordingly * partially type centroid * explicit tuple and undefined check * fix references to this * call constructor with new and casting * Revert "introduce TypedArray + NumericArray" This reverts commit cf2153871709ed78d390557f9653bb7d0b50a8ae. * explicit tuple * generics and import fixes * add unsigned 8 clamped arrray * back to literals * use arraytypes * fix return state * type more actions * Update client/src/util/actionHelpers.ts Co-authored-by: Timmy Huang * properly type dispatch * properly type thunk * use new dispatch * remove nullish coallescer * use AppDispatch * generic jsonrequest * use dispatch again * lint Co-authored-by: Timmy Huang --- client/__tests__/e2e/cellxgeneActions.ts | 13 +- client/__tests__/e2e/e2e.test.ts | 1 - client/__tests__/util/promiseLimit.test.ts | 4 +- client/__tests__/util/range.test.ts | 6 - client/src/actions/embedding.ts | 47 ++-- client/src/actions/index.ts | 200 +++++++++--------- client/src/annoMatrix/normalize.ts | 6 +- client/src/common/types/arraytypes.ts | 1 + .../brushableHistogram/histogram.tsx | 9 +- client/src/components/framework/toasters.ts | 6 +- client/src/globals.ts | 15 +- client/src/reducers/continuousSelection.ts | 21 +- client/src/reducers/index.ts | 8 +- client/src/reducers/userInfo.ts | 26 ++- client/src/util/actionHelpers.ts | 49 ++--- client/src/util/camera.ts | 70 +++--- client/src/util/catLabelSort.ts | 20 +- client/src/util/centroid.ts | 13 +- client/src/util/clamp.ts | 3 +- client/src/util/clip.ts | 14 +- client/src/util/finiteExtent.ts | 22 +- client/src/util/maybeScientific.ts | 11 +- client/src/util/nameCreators.ts | 45 ++-- client/src/util/parseBulkGeneString.ts | 3 +- client/src/util/parseRGB.ts | 15 +- client/src/util/promiseLimit.ts | 88 ++++---- client/src/util/range.ts | 36 ++-- client/src/util/renderThrottle.ts | 17 +- client/src/util/scaleLinear.ts | 12 +- client/src/util/scaleRGB.ts | 3 +- client/src/util/significantDigits.ts | 7 +- 31 files changed, 425 insertions(+), 366 deletions(-) diff --git a/client/__tests__/e2e/cellxgeneActions.ts b/client/__tests__/e2e/cellxgeneActions.ts index d54e884f..5a3333dd 100644 --- a/client/__tests__/e2e/cellxgeneActions.ts +++ b/client/__tests__/e2e/cellxgeneActions.ts @@ -94,10 +94,12 @@ export async function getAllCategoriesAndCounts(category: any) { .querySelector("[data-testclass='categorical-value']") .getAttribute("aria-label"); - const count = (row.querySelector( - "[data-testclass='categorical-value-count']" - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - ) as any).innerText; + const count = ( + row.querySelector( + "[data-testclass='categorical-value-count']" + // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. + ) as any + ).innerText; return [cat, count]; }) @@ -194,8 +196,7 @@ export async function expandCategory(category: any) { if (notExpanded) await clickOn(`${category}:category-expand`); } -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS. -export async function clip(min = 0, max = 100) { +export async function clip(min = "0", max = "100"): Promise { await clickOn("visualization-settings"); await clearInputAndTypeInto("clip-min-input", min); await clearInputAndTypeInto("clip-max-input", max); diff --git a/client/__tests__/e2e/e2e.test.ts b/client/__tests__/e2e/e2e.test.ts index f8f34ca7..2c9ad2ed 100644 --- a/client/__tests__/e2e/e2e.test.ts +++ b/client/__tests__/e2e/e2e.test.ts @@ -199,7 +199,6 @@ describe("clipping", () => { test("clip continuous", async () => { await goToPage(appUrlBase); - // @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string' is not assignable to par... Remove this comment to see the full error message await clip(data.clip.min, data.clip.max); const histBrushableAreaId = `histogram-${data.clip.metadata}-plot-brushable-area`; const coords = await calcDragCoordinates( diff --git a/client/__tests__/util/promiseLimit.test.ts b/client/__tests__/util/promiseLimit.test.ts index 897e1366..6b51ff0c 100644 --- a/client/__tests__/util/promiseLimit.test.ts +++ b/client/__tests__/util/promiseLimit.test.ts @@ -52,9 +52,7 @@ describe("PromiseLimit", () => { running -= 1; }; - // @ts-expect-error ts-migrate(2554) FIXME: Expected 3 arguments, but got 1. - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - await Promise.all(range(10).map((i: any) => plimit.add(() => callback(i)))); + await Promise.all(range(10).map(() => plimit.add(() => callback()))); expect(maxRunning).toEqual(2); }); diff --git a/client/__tests__/util/range.test.ts b/client/__tests__/util/range.test.ts index b7aa0a66..5da8821d 100644 --- a/client/__tests__/util/range.test.ts +++ b/client/__tests__/util/range.test.ts @@ -6,20 +6,14 @@ describe("range", () => { }); test("range(stop)", () => { - // @ts-expect-error ts-migrate(2554) FIXME: Expected 3 arguments, but got 1. expect(range(3)).toMatchObject([0, 1, 2]); - // @ts-expect-error ts-migrate(2554) FIXME: Expected 3 arguments, but got 1. expect(range(0)).toMatchObject([]); - // @ts-expect-error ts-migrate(2554) FIXME: Expected 3 arguments, but got 1. expect(range(1)).toMatchObject([0]); }); test("range(start,stop)", () => { - // @ts-expect-error ts-migrate(2554) FIXME: Expected 3 arguments, but got 2. expect(range(0, 0)).toMatchObject([]); - // @ts-expect-error ts-migrate(2554) FIXME: Expected 3 arguments, but got 2. expect(range(0, 2)).toMatchObject([0, 1]); - // @ts-expect-error ts-migrate(2554) FIXME: Expected 3 arguments, but got 2. expect(range(4, 8)).toMatchObject([4, 5, 6, 7]); }); diff --git a/client/src/actions/embedding.ts b/client/src/actions/embedding.ts index fa4835e6..d966a30e 100644 --- a/client/src/actions/embedding.ts +++ b/client/src/actions/embedding.ts @@ -2,7 +2,10 @@ action creators related to embeddings choice */ +import { Action, ActionCreator } from "redux"; +import { ThunkAction } from "redux-thunk"; import { AnnoMatrixObsCrossfilter } from "../annoMatrix"; +import type { AppDispatch, RootState } from "../reducers"; import { _setEmbeddingSubset } from "../util/stateManager/viewStackHelpers"; // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS. @@ -29,30 +32,26 @@ export async function _switchEmbedding( return [annoMatrix, obsCrossfilter]; } -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. -export const layoutChoiceAction = (newLayoutChoice: any) => async ( - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. - dispatch: any, - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. - getState: any -) => { - /* +export const layoutChoiceAction: ActionCreator< + ThunkAction, RootState, never, Action<"set layout choice">> +> = + (newLayoutChoice: string) => + async (dispatch: AppDispatch, getState: () => RootState): Promise => { + /* On layout choice, make sure we have selected all on the previous layout, AND the new layout. */ - const { - annoMatrix: prevAnnoMatrix, - obsCrossfilter: prevCrossfilter, - } = getState(); - const [annoMatrix, obsCrossfilter] = await _switchEmbedding( - prevAnnoMatrix, - prevCrossfilter, - newLayoutChoice - ); - dispatch({ - type: "set layout choice", - layoutChoice: newLayoutChoice, - obsCrossfilter, - annoMatrix, - }); -}; + const { annoMatrix: prevAnnoMatrix, obsCrossfilter: prevCrossfilter } = + getState(); + const [annoMatrix, obsCrossfilter] = await _switchEmbedding( + prevAnnoMatrix, + prevCrossfilter, + newLayoutChoice + ); + dispatch({ + type: "set layout choice", + layoutChoice: newLayoutChoice, + obsCrossfilter, + annoMatrix, + }); + }; diff --git a/client/src/actions/index.ts b/client/src/actions/index.ts index 5f68f0d3..49c5d115 100644 --- a/client/src/actions/index.ts +++ b/client/src/actions/index.ts @@ -1,3 +1,4 @@ +import type { Config } from "../globals"; import * as globals from "../globals"; import { AnnoMatrixLoader, AnnoMatrixObsCrossfilter } from "../annoMatrix"; import { @@ -11,6 +12,9 @@ import * as annoActions from "./annotation"; import * as viewActions from "./viewStack"; import * as embActions from "./embedding"; import * as genesetActions from "./geneset"; +import { AppDispatch, RootState } from "../reducers"; +import { EmbeddingSchema, Schema } from "../common/types/schema"; +import { UserInfoPayload } from "../reducers/userInfo"; // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. function setGlobalConfig(config: any) { @@ -36,35 +40,34 @@ async function userColorsFetchAndLoad(dispatch: any) { ); } -async function schemaFetch() { - return fetchJson("schema"); +async function schemaFetch(): Promise<{ schema: Schema }> { + return fetchJson<{ schema: Schema }>("schema"); } -// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. -async function configFetch(dispatch: any) { - return fetchJson("config").then((response) => { - const config = { ...globals.configDefaults, ...response.config }; +async function configFetch(dispatch: AppDispatch): Promise { + const response = await fetchJson<{ config: globals.Config }>("config"); + const config = { ...globals.configDefaults, ...response.config }; - setGlobalConfig(config); + setGlobalConfig(config); - dispatch({ - type: "configuration load complete", - config, - }); - return config; + dispatch({ + type: "configuration load complete", + config, }); + return config; } -// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. -async function userInfoFetch(dispatch: any) { - return fetchJson("userinfo").then((response) => { - const { userinfo: userInfo } = response || {}; - dispatch({ - type: "userInfo load complete", - userInfo, - }); - return userInfo; - }); +async function userInfoFetch(dispatch: AppDispatch): Promise { + return fetchJson<{ userinfo: UserInfoPayload }>("userinfo").then( + (response) => { + const { userinfo: userInfo } = response || {}; + dispatch({ + type: "userInfo load complete", + userInfo, + }); + return userInfo; + } + ); } // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. @@ -104,17 +107,17 @@ function prefetchEmbeddings(annoMatrix: any) { /* Application bootstrap */ -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS. -const doInitialDataLoad = () => - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - catchErrorsWrap(async (dispatch: any) => { +const doInitialDataLoad = (): (( + dispatch: AppDispatch, + getState: () => RootState +) => void) => + catchErrorsWrap(async (dispatch: AppDispatch) => { dispatch({ type: "initial data load start" }); try { const [config, schema] = await Promise.all([ configFetch(dispatch), - // @ts-expect-error ts-migrate(2554) FIXME: Expected 0 arguments, but got 1. - schemaFetch(dispatch), + schemaFetch(), userColorsFetchAndLoad(dispatch), userInfoFetch(dispatch), ]); @@ -137,8 +140,7 @@ const doInitialDataLoad = () => const layoutSchema = schema?.schema?.layout?.obs ?? []; if ( defaultEmbedding && - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - layoutSchema.some((s: any) => s.name === defaultEmbedding) + layoutSchema.some((s: EmbeddingSchema) => s.name === defaultEmbedding) ) { dispatch(embActions.layoutChoiceAction(defaultEmbedding)); } @@ -188,87 +190,89 @@ const dispatchDiffExpErrors = (dispatch: any, response: any) => { } }; -const requestDifferentialExpression = ( +const requestDifferentialExpression = + ( + // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. + set1: any, + // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. + set2: any, + num_genes = 50 + // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. + ) => // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. - set1: any, - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. - set2: any, - num_genes = 50 - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. -) => async (dispatch: any, getState: any) => { - dispatch({ type: "request differential expression started" }); - try { - /* + async (dispatch: any, getState: any) => { + dispatch({ type: "request differential expression started" }); + try { + /* Steps: 1. get the most differentially expressed genes 2. get expression data for each */ - const { annoMatrix } = getState(); - const varIndexName = annoMatrix.schema.annotations.var.index; + const { annoMatrix } = getState(); + const varIndexName = annoMatrix.schema.annotations.var.index; - // Legal values are null, Array or TypedArray. Null is initial state. - if (!set1) set1 = []; - if (!set2) set2 = []; + // Legal values are null, Array or TypedArray. Null is initial state. + if (!set1) set1 = []; + if (!set2) set2 = []; - // These lines ensure that we convert any TypedArray to an Array. - // This is necessary because JSON.stringify() does some very strange - // things with TypedArrays (they are marshalled to JSON objects, rather - // than being marshalled as a JSON array). - set1 = Array.isArray(set1) ? set1 : Array.from(set1); - set2 = Array.isArray(set2) ? set2 : Array.from(set2); + // These lines ensure that we convert any TypedArray to an Array. + // This is necessary because JSON.stringify() does some very strange + // things with TypedArrays (they are marshalled to JSON objects, rather + // than being marshalled as a JSON array). + set1 = Array.isArray(set1) ? set1 : Array.from(set1); + set2 = Array.isArray(set2) ? set2 : Array.from(set2); - const res = await fetch( - `${globals.API.prefix}${globals.API.version}diffexp/obs`, - { - method: "POST", - headers: new Headers({ - Accept: "application/json", - "Content-Type": "application/json", - }), - body: JSON.stringify({ - mode: "topN", - count: num_genes, - set1: { filter: { obs: { index: set1 } } }, - set2: { filter: { obs: { index: set2 } } }, - }), - credentials: "include", + const res = await fetch( + `${globals.API.prefix}${globals.API.version}diffexp/obs`, + { + method: "POST", + headers: new Headers({ + Accept: "application/json", + "Content-Type": "application/json", + }), + body: JSON.stringify({ + mode: "topN", + count: num_genes, + set1: { filter: { obs: { index: set1 } } }, + set2: { filter: { obs: { index: set2 } } }, + }), + credentials: "include", + } + ); + + if (!res.ok || res.headers.get("Content-Type") !== "application/json") { + return dispatchDiffExpErrors(dispatch, res); } - ); - if (!res.ok || res.headers.get("Content-Type") !== "application/json") { - return dispatchDiffExpErrors(dispatch, res); + const response = await res.json(); + const varIndex = await annoMatrix.fetch("var", varIndexName); + const diffexpLists = { negative: [], positive: [] }; + for (const polarity of Object.keys(diffexpLists)) { + // @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message + // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. + diffexpLists[polarity] = response[polarity].map((v: any) => [ + varIndex.at(v[0], varIndexName), + ...v.slice(1), + ]); + } + + /* then send the success case action through */ + return dispatch({ + type: "request differential expression success", + data: diffexpLists, + }); + } catch (error) { + return dispatch({ + type: "request differential expression error", + error, + }); } + }; - const response = await res.json(); - const varIndex = await annoMatrix.fetch("var", varIndexName); - const diffexpLists = { negative: [], positive: [] }; - for (const polarity of Object.keys(diffexpLists)) { - // @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - diffexpLists[polarity] = response[polarity].map((v: any) => [ - varIndex.at(v[0], varIndexName), - ...v.slice(1), - ]); - } - - /* then send the success case action through */ - return dispatch({ - type: "request differential expression success", - data: diffexpLists, - }); - } catch (error) { - return dispatch({ - type: "request differential expression error", - error, - }); - } -}; - -// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. -function fetchJson(pathAndQuery: any) { - return doJsonRequest( +function fetchJson(pathAndQuery: string): Promise { + return doJsonRequest( `${globals.API.prefix}${globals.API.version}${pathAndQuery}` - ); + ) as Promise; } export default { diff --git a/client/src/annoMatrix/normalize.ts b/client/src/annoMatrix/normalize.ts index 3360d265..1296cc80 100644 --- a/client/src/annoMatrix/normalize.ts +++ b/client/src/annoMatrix/normalize.ts @@ -80,10 +80,10 @@ export function normalizeWritableCategoricalSchema( ) { /* Ensure all enum writable / categorical schema have a categories array, that - the categories array contains all unique values in the data array, AND that + the categories array contains all unique values in the data array, AND that the array is UI sorted. */ - const categorySet = new Set( + const categorySet = new Set( col.summarizeCategorical().categories.concat(colSchema.categories ?? []) ); if (!categorySet.has(unassignedCategoryLabel)) { @@ -118,7 +118,7 @@ export function normalizeCategorical( // consolidate all categories from data and schema into a single list const colDataSummary = col.summarizeCategorical(); - const allCategories = new Set( + const allCategories = new Set( colDataSummary.categories.concat(colSchema.categories ?? []) ); diff --git a/client/src/common/types/arraytypes.ts b/client/src/common/types/arraytypes.ts index 3ec4456a..266b5be2 100644 --- a/client/src/common/types/arraytypes.ts +++ b/client/src/common/types/arraytypes.ts @@ -8,6 +8,7 @@ export type TypedArray = | Int8Array | Uint8Array + | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array diff --git a/client/src/components/brushableHistogram/histogram.tsx b/client/src/components/brushableHistogram/histogram.tsx index 51e7f786..7f7831a2 100644 --- a/client/src/components/brushableHistogram/histogram.tsx +++ b/client/src/components/brushableHistogram/histogram.tsx @@ -2,6 +2,7 @@ import React, { useEffect, useRef, useState } from "react"; import { interpolateCool } from "d3-scale-chromatic"; import * as d3 from "d3"; +import { AxisDomain } from "d3"; import maybeScientific from "../../util/maybeScientific"; import clamp from "../../util/clamp"; @@ -120,8 +121,12 @@ const Histogram = ({ d3 .axisBottom(x) .ticks(4) - // @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call. - .tickFormat(d3.format(maybeScientific(x))) + .tickFormat( + d3.format(maybeScientific(x)) as ( + dv: AxisDomain, + i: number + ) => string + ) ); /* Y AXIS */ diff --git a/client/src/components/framework/toasters.ts b/client/src/components/framework/toasters.ts index bffbd885..ce41956e 100644 --- a/client/src/components/framework/toasters.ts +++ b/client/src/components/framework/toasters.ts @@ -26,8 +26,10 @@ export const keepAroundErrorToast = (message: any) => /* a hard network error */ -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. -export const postNetworkErrorToast = (message: any, key = undefined) => +export const postNetworkErrorToast = ( + message: string, + key: string | undefined = undefined +): string => ToastTopCenter.show( { message, diff --git a/client/src/globals.ts b/client/src/globals.ts index d23867f6..5db99238 100644 --- a/client/src/globals.ts +++ b/client/src/globals.ts @@ -8,11 +8,24 @@ export const overflowCategoryLabel = ": all other labels"; /* default "unassigned" value for user-created categorical metadata */ export const unassignedCategoryLabel = "unassigned"; +/* rough shape of config object */ +export interface Config { + features: Record; + displayNames: Record; + parameters: { + "disable-diffexp"?: boolean; + "diffexp-may-be-slow"?: boolean; + default_embedding?: string; + [key: string]: unknown; + }; + links: Record; +} + /* these are default values for configuration the CLI may supply. See the REST API and CLI specs for more info. */ -export const configDefaults = { +export const configDefaults: Config = { features: {}, displayNames: {}, parameters: { diff --git a/client/src/reducers/continuousSelection.ts b/client/src/reducers/continuousSelection.ts index d80cffe6..8923c2b6 100644 --- a/client/src/reducers/continuousSelection.ts +++ b/client/src/reducers/continuousSelection.ts @@ -1,7 +1,23 @@ +import type { Action } from "redux"; + import { makeContinuousDimensionName } from "../util/nameCreators"; -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. -const ContinuousSelection = (state = {}, action: any) => { +import type { ContinuousNamespace } from "../util/nameCreators"; + +export interface ContinuousSelectionAction extends Action { + continuousNamespace: ContinuousNamespace; + selection: string; + range: [number, number]; +} + +export interface ContinuousSelectionState { + [name: string]: [number, number]; +} + +const ContinuousSelection = ( + state: ContinuousSelectionState = {}, + action: ContinuousSelectionAction +): ContinuousSelectionState => { switch (action.type) { case "reset subset": case "subset to selection": @@ -25,7 +41,6 @@ const ContinuousSelection = (state = {}, action: any) => { action.continuousNamespace, action.selection ); - // @ts-expect-error ts-migrate(2537) FIXME: Type '{}' has no matching index signature for type... Remove this comment to see the full error message const { [name]: deletedField, ...newState } = state; return newState; } diff --git a/client/src/reducers/index.ts b/client/src/reducers/index.ts index 8f07bfe4..633de304 100644 --- a/client/src/reducers/index.ts +++ b/client/src/reducers/index.ts @@ -1,5 +1,5 @@ -import { createStore, applyMiddleware } from "redux"; -import thunk from "redux-thunk"; +import { createStore, applyMiddleware, AnyAction } from "redux"; +import thunk, { ThunkDispatch } from "redux-thunk"; import cascadeReducers from "./cascade"; import undoable from "./undoable"; @@ -63,4 +63,8 @@ const Reducer = undoable( const store = createStore(Reducer, applyMiddleware(thunk, annoMatrixGC)); +export type RootState = ReturnType; + +export type AppDispatch = ThunkDispatch; + export default store; diff --git a/client/src/reducers/userInfo.ts b/client/src/reducers/userInfo.ts index 59b04d4a..1eb3088e 100644 --- a/client/src/reducers/userInfo.ts +++ b/client/src/reducers/userInfo.ts @@ -1,5 +1,27 @@ -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. -const UserInfo = (state = {}, action: any) => { +import { Action } from "redux"; + +export interface UserInfoAction extends Action, User { + userInfo: UserInfoPayload; + error: string; +} + +export interface UserInfoPayload { + is_authenticated: boolean; + username: string; + user_id: string; + email: string; + picture: string; +} + +export interface UserInfoState extends UserInfoPayload { + loading: boolean; + error: string | null; +} + +const UserInfo = ( + state: UserInfoState, + action: UserInfoAction +): UserInfoState => { switch (action.type) { case "initial data load start": return { diff --git a/client/src/util/actionHelpers.ts b/client/src/util/actionHelpers.ts index 82b874e8..4da579b5 100644 --- a/client/src/util/actionHelpers.ts +++ b/client/src/util/actionHelpers.ts @@ -1,15 +1,14 @@ import sortBy from "lodash.sortby"; /* XXX: cough, cough, ... */ import { postNetworkErrorToast } from "../components/framework/toasters"; +import type { AppDispatch, RootState } from "../reducers"; /* dispatch an action error to the user. Currently we use async toasts. */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. -let networkErrorToastKey: any = null; -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. -export const dispatchNetworkErrorMessageToUser = (message: any) => { +let networkErrorToastKey: string | null = null; +export const dispatchNetworkErrorMessageToUser = (message: string): void => { if (!networkErrorToastKey) { networkErrorToastKey = postNetworkErrorToast(message); } else { @@ -20,12 +19,12 @@ export const dispatchNetworkErrorMessageToUser = (message: any) => { /* Catch unexpected errors and make sure we don't lose them! */ -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. -export function catchErrorsWrap(fn: any, dispatchToUser = false) { - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. - return (dispatch: any, getState: any) => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - fn(dispatch, getState).catch((error: any) => { +export function catchErrorsWrap( + fn: (dispatch: AppDispatch, getState: () => RootState) => Promise, + dispatchToUser = false +) { + return (dispatch: AppDispatch, getState: () => RootState): void => { + fn(dispatch, getState).catch((error: Error) => { console.error(error); if (dispatchToUser) { dispatchNetworkErrorMessageToUser(error.message); @@ -39,8 +38,10 @@ export function catchErrorsWrap(fn: any, dispatchToUser = false) { * Wrapper to perform async fetch with some modest error handling * and decoding. Arguments are identical to standard fetch. */ -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. -export const doFetch = async (url: any, init = {}) => { +export const doFetch = async ( + url: string, + init?: RequestInit +): Promise => { try { // add defaults to the fetch init param. init = { @@ -48,13 +49,11 @@ export const doFetch = async (url: any, init = {}) => { credentials: "include", ...init, }; - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - const acceptType = (init as any).headers?.get("Accept"); + const acceptType = (init.headers as Headers)?.get("Accept"); const res = await fetch(url, init); if ( res.ok && - // @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'. - (!acceptType || res.headers.get("Content-Type").includes(acceptType)) + (!acceptType || res.headers?.get("Content-Type")?.includes(acceptType)) ) { return res; } @@ -74,8 +73,10 @@ export const doFetch = async (url: any, init = {}) => { /* Wrapper to perform an async fetch and JSON decode response. */ -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. -export const doJsonRequest = async (url: any, init = {}) => { +export const doJsonRequest = async ( + url: string, + init?: RequestInit +): Promise => { const res = await doFetch(url, { ...init, headers: new Headers({ Accept: "application/json" }), @@ -86,8 +87,10 @@ export const doJsonRequest = async (url: any, init = {}) => { /* Wrapper to perform an async fetch for binary data. */ -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. -export const doBinaryRequest = async (url: any, init = {}) => { +export const doBinaryRequest = async ( + url: string, + init?: RequestInit +): Promise => { const res = await doFetch(url, { ...init, headers: new Headers({ Accept: "application/octet-stream" }), @@ -110,13 +113,11 @@ Parameters: So [1, 2, 3, 4, 10, 11, 14] -> [ [1, 4], [10, 11], 14] */ -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS. export const rangeEncodeIndices = ( - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. - indices: any, + indices: Array, minRangeLength = 3, sorted = false -) => { +): Array => { if (indices.length === 0) { return indices; } diff --git a/client/src/util/camera.ts b/client/src/util/camera.ts index 6df7d644..93353c28 100644 --- a/client/src/util/camera.ts +++ b/client/src/util/camera.ts @@ -1,4 +1,5 @@ import { vec2, mat3 } from "gl-matrix"; +import clamp from "./clamp"; const EPSILON = 0.000001; @@ -11,56 +12,49 @@ const panBound = 0.8; const scratch0 = new Float32Array(16); const scratch1 = new Float32Array(16); -// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. -function clamp(val: any, rng: any) { - return Math.max(Math.min(val, rng[1]), rng[0]); -} - class Camera { - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - canvas: any; + canvas: HTMLCanvasElement; - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - prevEvent: any; + prevEvent: { + clientX: number; + clientY: number; + type: string; + }; - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - viewMatrix: any; + viewMatrix: mat3; - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - viewMatrixInv: any; + viewMatrixInv: mat3; - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - constructor(canvas: any) { + constructor(canvas: HTMLCanvasElement) { this.prevEvent = { clientX: 0, clientY: 0, - type: 0, + type: "", }; this.canvas = canvas; this.viewMatrix = mat3.create(); this.viewMatrixInv = mat3.create(); } - view() { + view(): mat3 { return this.viewMatrix; } - invView() { + invView(): mat3 { return this.viewMatrixInv; } - distance() { + distance(): number { return this.viewMatrix[0]; } - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - pan(dx: any, dy: any) { + pan(dx: number, dy: number): void { const m = this.viewMatrix; - const dyRange = [ + const dyRange: [number, number] = [ -panBound - (m[7] + 1) / m[4], panBound - (m[7] - 1) / m[4], ]; - const dxRange = [ + const dxRange: [number, number] = [ -panBound - (m[6] + 1) / m[0], panBound - (m[6] - 1) / m[0], ]; @@ -74,13 +68,12 @@ class Camera { mat3.invert(this.viewMatrixInv, m); } - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - zoomAt(d: any, x = 0, y = 0) { + zoomAt(d: number, x = 0, y = 0): void { /* Camera zoom at [x,y] */ const m = this.viewMatrix; - const bounds = [-panBound, panBound]; + const bounds: [number, number] = [-panBound, panBound]; x = clamp(x, bounds); y = clamp(y, bounds); @@ -98,15 +91,18 @@ class Camera { Event handling */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - flush(e: any) { + flush(e: MouseEvent) { this.prevEvent.type = e.type; this.prevEvent.clientX = e.clientX; this.prevEvent.clientY = e.clientY; } - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - localPosition(target: any, canvasX: any, canvasY: any, projectionInvTF: any) { + localPosition( + target: HTMLCanvasElement, + canvasX: number, + canvasY: number, + projectionInvTF: mat3 + ): vec2 { /* Convert mouse position to local */ @@ -126,8 +122,7 @@ class Camera { return pos; } - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - mousePan(e: any, projectionTF: any) { + mousePan(e: MouseEvent, projectionTF: mat3): true { const projectionInvTF = mat3.invert(scratch0, projectionTF); const pos = this.localPosition( this.canvas, @@ -147,8 +142,7 @@ class Camera { return true; } - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - wheelZoom(e: any, projectionTF: any) { + wheelZoom(e: WheelEvent, projectionTF: mat3): true { const { height } = this.canvas; const { deltaY, deltaMode, clientX, clientY } = e; const scale = scaleSpeed * (deltaMode === 1 ? 12 : 1) * (deltaY || 0); @@ -164,8 +158,7 @@ class Camera { return true; } - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - handleEvent(e: any, projectionTF: any) { + handleEvent(e: MouseEvent, projectionTF: mat3): boolean { /* process the event, and return true if camera view changed */ @@ -181,7 +174,7 @@ class Camera { } case "wheel": { - viewChanged = this.wheelZoom(e, projectionTF); + viewChanged = this.wheelZoom(e as WheelEvent, projectionTF); this.flush(e); break; } @@ -194,8 +187,7 @@ class Camera { } } -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. -function attachCamera(canvas: any) { +function attachCamera(canvas: HTMLCanvasElement): Camera { return new Camera(canvas); } diff --git a/client/src/util/catLabelSort.ts b/client/src/util/catLabelSort.ts index e1a25de6..1bf29bf2 100644 --- a/client/src/util/catLabelSort.ts +++ b/client/src/util/catLabelSort.ts @@ -11,24 +11,23 @@ TL;DR: sort order is: import isNumber from "is-number"; import * as globals from "../globals"; -// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. -function caseInsensitiveCompare(a: any, b: any) { +function caseInsensitiveCompare(a: string, b: string): number { const textA = String(a).toUpperCase(); const textB = String(b).toUpperCase(); return textA < textB ? -1 : textA > textB ? 1 : 0; } -// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. -const catLabelSort = (isUserAnno: boolean, values: any[]): any[] => { +const catLabelSort = ( + isUserAnno: boolean, + values: Array +): Array => { /* this sort could be memoized for perf */ const strings: string[] = []; - const ints: number[] = []; - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - const unassignedOrNaN: any = []; + const ints: string[] = []; + const unassignedOrNaN: string[] = []; - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - values.forEach((v: any) => { + values.forEach((v: string) => { if (isUserAnno && v === globals.unassignedCategoryLabel) { unassignedOrNaN.push(v); } else if (String(v).toLowerCase() === "nan") { @@ -44,8 +43,7 @@ const catLabelSort = (isUserAnno: boolean, values: any[]): any[] => { ints.sort((a, b) => +a - +b); unassignedOrNaN.sort(caseInsensitiveCompare); - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - return (ints).concat(strings, unassignedOrNaN); + return ints.concat(strings, unassignedOrNaN); }; export default catLabelSort; diff --git a/client/src/util/centroid.ts b/client/src/util/centroid.ts index f40faac3..f4201788 100644 --- a/client/src/util/centroid.ts +++ b/client/src/util/centroid.ts @@ -26,8 +26,7 @@ label -> { const getCoordinatesByLabel = ( // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. schema: any, - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - categoryName: any, + categoryName: string, categoryDf: Dataframe, // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. layoutChoice: any, @@ -73,7 +72,7 @@ const getCoordinatesByLabel = ( let coords = coordsByCategoryLabel.get(label); if (coords === undefined) { // Get the number of cells which are in the label - // @ts-expect-error ts-migrate(2538) FIXME: Type 'unknown' cannot be used as an index type. + // @ts-expect-error ts-migrate(2538) FIXME: Blocked by StateManager/ControlsHelpers const numInLabel = categoryValueCounts[labelIndex]; coords = { hasFinite: false, @@ -99,7 +98,7 @@ const getCoordinatesByLabel = ( return coordsByCategoryLabel; }; -/* +/* calcMedianCentroid calculates the median coordinates for labels in a given category label -> [x-Coordinate, y-Coordinate] @@ -108,8 +107,7 @@ const getCoordinatesByLabel = ( const calcMedianCentroid = ( // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. schema: any, - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - categoryName: any, + categoryName: string, categoryDf: Dataframe, // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. layoutChoice: any, @@ -151,8 +149,7 @@ const hashMedianCentroid = ( // @ts-expect-error ts-migrate(6133) FIXME: 'schema' is declared but its value is never read. // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. schema: any, - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - categoryName: any, + categoryName: string, categoryDf: Dataframe, // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. layoutChoice: any, diff --git a/client/src/util/clamp.ts b/client/src/util/clamp.ts index 715ac18f..7a27902e 100644 --- a/client/src/util/clamp.ts +++ b/client/src/util/clamp.ts @@ -8,7 +8,6 @@ * @returns a number */ -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. -export default function clamp(val: any, rng: any) { +export default function clamp(val: number, rng: [number, number]): number { return Math.max(Math.min(val, rng[1]), rng[0]); } diff --git a/client/src/util/clip.ts b/client/src/util/clip.ts index 735c8ab9..6d7dc118 100644 --- a/client/src/util/clip.ts +++ b/client/src/util/clip.ts @@ -1,17 +1,23 @@ +import { NumberArray } from "../common/types/arraytypes"; + /* clip - clip all values in a Array or TypedArray, IN PLACE. Values in array are clipped if less than `lower` or greater than `upper`. If `setTo` is undefined, values less than `lower` will be set to `lower`, -and values greater than `upper` will be set to `upper`. +and values greater than `upper` will be set to `upper`. -If `setTo` is not undefined, values outside the [lower, upper] range will be set to +If `setTo` is not undefined, values outside the [lower, upper] range will be set to `setTo`. */ -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. -export default function clip(arr: any, lower: any, upper: any, setTo: any) { +export default function clip( + arr: NumberArray, + lower: number, + upper: number, + setTo?: number +): NumberArray { const lowerSet = setTo === undefined ? lower : setTo; const upperSet = setTo === undefined ? upper : setTo; for (let i = 0, l = arr.length; i < l; i += 1) { diff --git a/client/src/util/finiteExtent.ts b/client/src/util/finiteExtent.ts index e3352ce2..d778aa01 100644 --- a/client/src/util/finiteExtent.ts +++ b/client/src/util/finiteExtent.ts @@ -6,8 +6,11 @@ If undefined or empty array, or array contains only non-finite numbers, will return [undefined, undefined] */ -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. -function finiteExtent(tarr: any) { +import type { TypedArray } from "../common/types/arraytypes"; + +function finiteExtent( + tarr: TypedArray +): [number, number] | [undefined, undefined] { let min; let max; let i; @@ -21,14 +24,17 @@ function finiteExtent(tarr: any) { break; } } - for (; i < tarr.length; i += 1) { - const val = tarr[i]; - if (Number.isFinite(val)) { - if (min > val) min = val; - if (max < val) max = val; + if (min !== undefined && max !== undefined) { + for (; i < tarr.length; i += 1) { + const val = tarr[i]; + if (Number.isFinite(val)) { + if (min > val) min = val; + if (max < val) max = val; + } } + return [min, max]; } - return [min, max]; + return [undefined, undefined]; } export default finiteExtent; diff --git a/client/src/util/maybeScientific.ts b/client/src/util/maybeScientific.ts index a3e25151..8f701c45 100644 --- a/client/src/util/maybeScientific.ts +++ b/client/src/util/maybeScientific.ts @@ -1,3 +1,4 @@ +import { ScaleLinear } from "d3"; import significantDigits from "./significantDigits"; /** @@ -10,14 +11,14 @@ import significantDigits from "./significantDigits"; * @returns - the number formatted as scientific, if it's big enough */ -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. -export default function maybeScientific(x: any) { +export default function maybeScientific( + x: ScaleLinear +): string { let format = ","; const _ticks = x.ticks(4); - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - if (x.domain().some((n: any) => Math.abs(n) >= 10000)) { - /* + if (x.domain().some((n: number) => Math.abs(n) >= 10000)) { + /* heuristic: if the last tick d3 wants to render has one significant digit ie., 2000, render 2e+3, but if it's anything else ie., 42000000 render 4.20e+n diff --git a/client/src/util/nameCreators.ts b/client/src/util/nameCreators.ts index 015884c6..f308e79c 100644 --- a/client/src/util/nameCreators.ts +++ b/client/src/util/nameCreators.ts @@ -13,43 +13,40 @@ anno matrix namespaces. It is still used by the component tier. */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. -const makeDimensionName = (namespace: any, key: any) => `${namespace}_${key}`; +const makeDimensionName = (namespace: string, key: string): string => + `${namespace}_${key}`; -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. -export const layoutDimensionName = (key: any) => +export const layoutDimensionName = (key: string): string => makeDimensionName("layout", key); -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. -export const obsAnnoDimensionName = (key: any) => + +export const obsAnnoDimensionName = (key: string): string => makeDimensionName("obsAnno", key); -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. -export const diffexpDimensionName = (key: any) => + +export const diffexpDimensionName = (key: string): string => makeDimensionName("varData_diffexp", key); -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. -export const userDefinedDimensionName = (key: any) => + +export const userDefinedDimensionName = (key: string): string => makeDimensionName("varData_userDefined", key); -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. -export const geneSetSummaryDimensionName = (key: any) => + +export const geneSetSummaryDimensionName = (key: string): string => makeDimensionName("geneSetSummary", key); +export interface ContinuousNamespace { + isObs?: boolean; + isDiffExp?: boolean; + isUserDefined?: boolean; + isGeneSetSummary?: boolean; +} + /* - continuousNamespace = { - isObs: true, - isDiffExp: false, - isUserDefined: false, - isGeneSet: false, - } ie., makeContinuousDimensionName(continuousNamespace = {isObs: true}, "total_reads") see: histogram brush, as it doesn't know what type of continuous it was with only field */ -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS. export const makeContinuousDimensionName = ( - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. - continuousNamespace: any, - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. - key: any -) => { + continuousNamespace: ContinuousNamespace, + key: string +): string => { let name; if (continuousNamespace.isObs) { name = obsAnnoDimensionName(key); diff --git a/client/src/util/parseBulkGeneString.ts b/client/src/util/parseBulkGeneString.ts index 6dbe58e5..33b24625 100644 --- a/client/src/util/parseBulkGeneString.ts +++ b/client/src/util/parseBulkGeneString.ts @@ -6,7 +6,6 @@ import pull from "lodash.pull"; import uniq from "lodash.uniq"; -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. -export default function parseBulkGeneString(geneString: any) { +export default function parseBulkGeneString(geneString: string): Array { return pull(uniq(geneString.split(/[ ,]+/)), ""); } diff --git a/client/src/util/parseRGB.ts b/client/src/util/parseRGB.ts index 98a2083e..be1e2648 100644 --- a/client/src/util/parseRGB.ts +++ b/client/src/util/parseRGB.ts @@ -4,32 +4,27 @@ import scaleRGB from "./scaleRGB"; // to do this operation. This lets us have speed, but keep the pleasant ability // to talk about colors by their text description eg, 'rgb(0,0,1)' // -const colorCache = {}; +const colorCache = {} as { [key: string]: [number, number, number] }; -// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. -function parseColorName(c: any) { +function parseColorName(c: string): [number, number, number] { if (c[0] !== "#") { const _c = c.replace(/[^\d,.]/g, "").split(","); return [scaleRGB(+_c[0]), scaleRGB(+_c[1]), scaleRGB(+_c[2])]; } const parsedHex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(c); + if (!parsedHex || parsedHex.length < 4) + throw new Error(`Invalid hex color: ${c}`); return [ - // @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'. scaleRGB(parseInt(parsedHex[1], 16)), - // @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'. scaleRGB(parseInt(parsedHex[2], 16)), - // @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'. scaleRGB(parseInt(parsedHex[3], 16)), ]; } -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. -export default (c: any) => { - // @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message +export default (c: string): [number, number, number] => { let cv = colorCache[c]; if (!cv) { cv = parseColorName(c); - // @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message colorCache[c] = cv; } return cv; diff --git a/client/src/util/promiseLimit.ts b/client/src/util/promiseLimit.ts index aea61444..eb928fb4 100644 --- a/client/src/util/promiseLimit.ts +++ b/client/src/util/promiseLimit.ts @@ -28,37 +28,55 @@ Priority is a numeric value. Lower first. Stable ordering. import TinyQueue from "tinyqueue"; -// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'a' implicitly has an 'any' type. -function compare(a, b) { +function compare( + a: PromiseLimitQueueItem, + b: PromiseLimitQueueItem +): number { const diff = a.priority - b.priority; if (diff) return diff; return a.order - b.order; } -export default class PromiseLimit { +interface PromiseLimitQueueItem { + priority: number; + order: number; + resolve: (value: T | PromiseLike) => void; + reject: (reason?: unknown) => void; + fn: (...args: Array) => Promise; + args: Array; +} + +export default class PromiseLimit { + queue: TinyQueue>; + + maxConcurrency: number; + + pending: number; + + insertCounter: number; + constructor(maxConcurrency = 5) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - (this as any).queue = new TinyQueue([], compare); - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - (this as any).maxConcurrency = maxConcurrency; - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - (this as any).pending = 0; - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - (this as any).insertCounter = 0; + this.queue = new TinyQueue>( + new Array>(), + compare + ); + this.maxConcurrency = maxConcurrency; + this.pending = 0; + this.insertCounter = 0; } - // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'p' implicitly has an 'any' type. - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS. - priorityAdd(p, fn, ...args) { + priorityAdd( + p: number, + fn: () => Promise, + ...args: Array + ): Promise { // p - numermic priority (lower first) // fn - must return a promise // args - will be passed to fn return this._push(p, fn, args); } - // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'fn' implicitly has an 'any' type. - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS. - add(fn, ...args) { + add(fn: () => Promise, ...args: Array): Promise { // fn - must return a promise // args - will be passed to fn return this._push(0, fn, args); @@ -68,35 +86,25 @@ export default class PromiseLimit { Private below **/ - // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'priority' implicitly has an 'any' type. - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS. - _push(priority, fn, args) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - const order = (this as any).insertCount; - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - (this as any).insertCount += 1; + _push( + priority: number, + fn: () => Promise, + args: Array + ): Promise { + const order = this.insertCounter; + this.insertCounter += 1; return new Promise((resolve, reject) => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - (this as any).queue.push({ priority, order, fn, args, resolve, reject }); + this.queue.push({ priority, order, fn, args, resolve, reject }); this._resolveNext(false); }); } - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS. - _resolveNext = (completed = true) => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - if (completed) (this as any).pending -= 1; + _resolveNext = (completed = true): void => { + if (completed) this.pending -= 1; - while ( - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - (this as any).queue.length > 0 && - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - (this as any).pending < (this as any).maxConcurrency - ) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - const task = (this as any).queue.pop(); // order of insertion - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - (this as any).pending += 1; + while (this.queue.length > 0 && this.pending < this.maxConcurrency) { + const task = this.queue.pop() as PromiseLimitQueueItem; // order of insertion + this.pending += 1; const { resolve, reject, fn, args } = task; try { diff --git a/client/src/util/range.ts b/client/src/util/range.ts index c05f0869..1562f151 100644 --- a/client/src/util/range.ts +++ b/client/src/util/range.ts @@ -22,38 +22,44 @@ rangeFill(array, start, step) -> array */ -// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'arr' implicitly has an 'any' type. -function _doFill(arr, start, step, count) { +import { TypedArray, NumberArray } from "../common/types/arraytypes"; + +function _doFill( + arr: T, + start: number, + step: number, + count: number +): T { for (let idx = 0, val = start; idx < count; idx += 1, val += step) { arr[idx] = val; } return arr; } -// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'arr' implicitly has an 'any' type. -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS. -export function rangeFill(arr, start = 0, step = 1) { +export function rangeFill(arr: NumberArray, start = 0, step = 1): NumberArray { return _doFill(arr, start, step, arr.length); } -// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'start' implicitly has an 'any' type. -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS. -export function range(start, stop, step) { +export function range( + start: number, + stop?: number, + step?: number +): Array { if (start === undefined) return []; if (stop === undefined) { stop = start; start = 0; } - step = step || 1; // catch undefind and zero + step = step || 1; // catch undefined and zero const len = Math.max(Math.ceil((stop - start) / step), 0); return _doFill(new Array(len), start, step, len); } -// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'start' implicitly has an 'any' type. -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS. -export function linspace(start, stop, nsteps) { - // @ts-expect-error ts-migrate(2363) FIXME: The right-hand side of an arithmetic operation mus... Remove this comment to see the full error message - const delta = (stop - start) / (nsteps - 1).toFixed(); - // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'i' implicitly has an 'any' type. +export function linspace( + start: number, + stop: number, + nsteps: number +): Array { + const delta = (stop - start) / Number((nsteps - 1).toFixed()); return range(0, nsteps, 1).map((i) => start + i * delta); } diff --git a/client/src/util/renderThrottle.ts b/client/src/util/renderThrottle.ts index 6f0c8439..ea97d01e 100644 --- a/client/src/util/renderThrottle.ts +++ b/client/src/util/renderThrottle.ts @@ -1,20 +1,17 @@ -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. -export default function renderThrottle(callback: any) { +export default function renderThrottle( + callback: (this: T) => void +): (this: T) => void { /* This wraps a call to requestAnimationFrame(), enforcing a single render callback at any given time (ie, you can call this any number of times, and it will coallesce multiple inter-frame calls into a single render). */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - let rafCurrentlyInProgress: any = null; - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - return function f(this: any) { - if (rafCurrentlyInProgress) return; - // eslint-disable-next-line @typescript-eslint/no-this-alias --- FIXME: disabled temporarily on migrate to TS. - const context = this; + let rafCurrentlyInProgress: number | null = null; + return function f(this: T) { + if (rafCurrentlyInProgress) return; // eslint-disable-next-line @typescript-eslint/no-this-alias --- required for functionality rafCurrentlyInProgress = window.requestAnimationFrame(() => { - callback.apply(context); + callback.call(this); rafCurrentlyInProgress = null; }); }; diff --git a/client/src/util/scaleLinear.ts b/client/src/util/scaleLinear.ts index 0701ab68..1e9dd494 100644 --- a/client/src/util/scaleLinear.ts +++ b/client/src/util/scaleLinear.ts @@ -6,18 +6,18 @@ // myScale(0) === -1 // this is is equivalent to d3.scaleLinear().domain([0,1]).range([-1,1]) -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. -export default (domain: any, range: any) => { +export default ( + domain: [number, number], + range: [number, number] +): ((value: number) => number) => { const domainStart = domain[0]; const scale = (range[1] - range[0]) / (domain[1] - domain[0]); const invScale = 1 / scale; const rangeStart = range[0]; - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - const f = (value: any) => (value - domainStart) * scale + rangeStart; + const f = (value: number) => (value - domainStart) * scale + rangeStart; // inverter - // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. - f.invert = (value: any) => (value - rangeStart) * invScale + domainStart; + f.invert = (value: number) => (value - rangeStart) * invScale + domainStart; return f; }; diff --git a/client/src/util/scaleRGB.ts b/client/src/util/scaleRGB.ts index c86ced8b..5c065dba 100644 --- a/client/src/util/scaleRGB.ts +++ b/client/src/util/scaleRGB.ts @@ -1,5 +1,4 @@ -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. -export default (input: any) => { +export default (input: number): number => { const outputMax = 1; const outputMin = 0; diff --git a/client/src/util/significantDigits.ts b/client/src/util/significantDigits.ts index 4d3107db..287d65f1 100644 --- a/client/src/util/significantDigits.ts +++ b/client/src/util/significantDigits.ts @@ -1,10 +1,11 @@ -/* +/* via https://github.com/nodef/extra-number/blob/master/scripts/significantDigits.js */ -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. -export default (n: any) => +const significantDigits = (n: number): number => n .toExponential() .replace(/e[+\-0-9]*$/, "") .replace(/^0\.?0*|\./, "").length; + +export default significantDigits;