diff --git a/src/Typesense/Aliases.ts b/src/Typesense/Aliases.ts index 0b3942e0..786ec541 100644 --- a/src/Typesense/Aliases.ts +++ b/src/Typesense/Aliases.ts @@ -31,7 +31,7 @@ export default class Aliases { return this.apiCall.get(RESOURCEPATH); } - private endpointPath(aliasName): string { + private endpointPath(aliasName: string): string { return `${Aliases.RESOURCEPATH}/${aliasName}`; } diff --git a/src/Typesense/ApiCall.ts b/src/Typesense/ApiCall.ts index b56c2115..537c7b2a 100644 --- a/src/Typesense/ApiCall.ts +++ b/src/Typesense/ApiCall.ts @@ -19,6 +19,7 @@ const UNHEALTHY = false; interface Node extends NodeConfiguration { isHealthy: boolean; index: string | number; + lastAccessTimestamp: number; } export default class ApiCall { @@ -340,7 +341,7 @@ export default class ApiCall { return candidateNode; } - nodeDueForHealthcheck(node, requestNumber = 0): boolean { + nodeDueForHealthcheck(node: Node, requestNumber = 0): boolean { const isDueForHealthcheck = Date.now() - node.lastAccessTimestamp > this.healthcheckIntervalSeconds * 1000; @@ -364,12 +365,12 @@ export default class ApiCall { }); } - setNodeHealthcheck(node, isHealthy): void { + setNodeHealthcheck(node: Node, isHealthy: boolean): void { node.isHealthy = isHealthy; node.lastAccessTimestamp = Date.now(); } - uriFor(endpoint: string, node): string { + uriFor(endpoint: string, node: NodeConfiguration): string { if (node.url != null) { return `${node.url}${endpoint}`; } @@ -377,7 +378,7 @@ export default class ApiCall { } defaultHeaders(): any { - const defaultHeaders = {}; + const defaultHeaders: Record = {}; if (!this.sendApiKeyAsQueryParam) { defaultHeaders[APIKEYHEADERNAME] = this.apiKey; } @@ -385,7 +386,7 @@ export default class ApiCall { return defaultHeaders; } - async timer(seconds): Promise { + async timer(seconds: number): Promise { return new Promise((resolve) => setTimeout(resolve, seconds * 1000)); } diff --git a/src/Typesense/Configuration.ts b/src/Typesense/Configuration.ts index cdbcdb5d..efc7f221 100644 --- a/src/Typesense/Configuration.ts +++ b/src/Typesense/Configuration.ts @@ -2,25 +2,28 @@ import * as logger from "loglevel"; import { Logger, LogLevelDesc } from "loglevel"; import { MissingConfigurationError } from "./Errors"; -export interface NodeConfiguration { +export interface NodeConfigurationWithHostname { host: string; port: number; protocol: string; path?: string; - url?: string; } -export interface NodeConfigurationWithHostname { - host: string; - port: number; - protocol: string; - path?: string; +export interface NodeConfiguration extends NodeConfigurationWithHostname { + url?: string; } export interface NodeConfigurationWithUrl { url: string; } +type NodeType = NodeConfiguration | NodeConfigurationWithHostname | NodeConfigurationWithUrl | undefined; + + +function isNodeConfigurationWithHostname(node: NodeType): node is NodeConfigurationWithHostname { + return node !== undefined && (node as NodeConfigurationWithHostname).protocol !== undefined; +} + export interface ConfigurationOptions { apiKey: string; nodes: @@ -166,49 +169,29 @@ export default class Configuration { return ( !["protocol", "host", "port", "path"].every((key) => { return node.hasOwnProperty(key); - }) && node["url"] == null + }) && node.hasOwnProperty("url") == null ); } private setDefaultPathInNode( - node: - | NodeConfiguration - | NodeConfigurationWithHostname - | NodeConfigurationWithUrl - | undefined - ): - | NodeConfiguration - | NodeConfigurationWithHostname - | NodeConfigurationWithUrl - | undefined { - if (node != null && !node.hasOwnProperty("path")) { - node["path"] = ""; - } + node: NodeType + ): NodeType { + if (isNodeConfigurationWithHostname(node)) { + node.path = ""; + } return node; } private setDefaultPortInNode( - node: - | NodeConfiguration - | NodeConfigurationWithHostname - | NodeConfigurationWithUrl - | undefined - ): - | NodeConfiguration - | NodeConfigurationWithHostname - | NodeConfigurationWithUrl - | undefined { - if ( - node != null && - !node.hasOwnProperty("port") && - node.hasOwnProperty("protocol") - ) { - switch (node["protocol"]) { + node: NodeType + ): NodeType { + if (isNodeConfigurationWithHostname(node)) { + switch (node.protocol) { case "https": - node["port"] = 443; + node.port = 443; break; case "http": - node["port"] = 80; + node.port = 80; break; } } @@ -233,7 +216,7 @@ export default class Configuration { } } - private shuffleArray(array) { + private shuffleArray(array: object[]) { for (let i = array.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [array[i], array[j]] = [array[j], array[i]]; diff --git a/src/Typesense/Documents.ts b/src/Typesense/Documents.ts index 48415391..acb3649d 100644 --- a/src/Typesense/Documents.ts +++ b/src/Typesense/Documents.ts @@ -248,7 +248,8 @@ export default class Documents ): Promise { if (!document) throw new Error("No document provided"); - if (options["filter_by"] != null) { + // @ts-expect-error filter_by does not exist in options + if (options ["filter_by"] != null) { return this.apiCall.patch( this.endpointPath(), document, diff --git a/src/Typesense/Errors/ImportError.ts b/src/Typesense/Errors/ImportError.ts index 94ffe3e9..f9934725 100644 --- a/src/Typesense/Errors/ImportError.ts +++ b/src/Typesense/Errors/ImportError.ts @@ -1,9 +1,9 @@ import TypesenseError from "./TypesenseError"; -import { ImportResponseFail } from "../Documents"; +import { ImportResponseFail, ImportResponse } from "../Documents"; export default class ImportError extends TypesenseError { - importResults: ImportResponseFail; - constructor(message, importResults) { + importResults: ImportResponseFail | ImportResponse[]; + constructor(message: string, importResults: ImportResponseFail | ImportResponse[]) { super(message); this.importResults = importResults; } diff --git a/src/Typesense/MultiSearch.ts b/src/Typesense/MultiSearch.ts index 036de8df..7cab0bb6 100644 --- a/src/Typesense/MultiSearch.ts +++ b/src/Typesense/MultiSearch.ts @@ -54,12 +54,12 @@ export default class MultiSearch { .cacheSearchResultsForSeconds, }: { cacheSearchResultsForSeconds?: number } = {} ): Promise> { - const additionalHeaders = {}; + const additionalHeaders: Record = {}; if (this.useTextContentType) { additionalHeaders["content-type"] = "text/plain"; } - const additionalQueryParams = {}; + const additionalQueryParams: Record = {}; if (this.configuration.useServerSideSearchCache === true) { additionalQueryParams["use_cache"] = true; } diff --git a/src/Typesense/SearchOnlyDocuments.ts b/src/Typesense/SearchOnlyDocuments.ts index 5efb68fc..ab177c13 100644 --- a/src/Typesense/SearchOnlyDocuments.ts +++ b/src/Typesense/SearchOnlyDocuments.ts @@ -36,12 +36,14 @@ export class SearchOnlyDocuments abortSignal = null, }: SearchOptions = {} ): Promise> { - const additionalQueryParams = {}; + const additionalQueryParams: Record = {}; if (this.configuration.useServerSideSearchCache === true) { additionalQueryParams["use_cache"] = true; } for (const key in searchParameters) { + // @ts-expect-error allow random lookup if (Array.isArray(searchParameters[key])) { + // @ts-expect-error allow random lookup additionalQueryParams[key] = searchParameters[key].join(","); } } diff --git a/tsconfig.json b/tsconfig.json index 7938271c..70f9bc8c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -27,7 +27,7 @@ /* Strict Type-Checking Options */ "strict": true /* Enable all strict type-checking options. */, - "noImplicitAny": false /* Raise error on expressions and declarations with an implied 'any' type. */, + "noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */, // "strictNullChecks": true, /* Enable strict null checks. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */