diff --git a/packages/graphile-build-pg/src/QueryBuilder.d.ts b/packages/graphile-build-pg/src/QueryBuilder.d.ts index dde40a113..2baa3ecbc 100644 --- a/packages/graphile-build-pg/src/QueryBuilder.d.ts +++ b/packages/graphile-build-pg/src/QueryBuilder.d.ts @@ -19,7 +19,7 @@ export type CursorValue = Array; export type CursorComparator = (val: CursorValue, isAfter: boolean) => void; export default class QueryBuilder { - public parentQueryBuilder: QueryBuilder | void; + public parentQueryBuilder: QueryBuilder | undefined; public context: GraphQLContext; public rootValue: any; public beforeLock(field: string, fn: () => void): void; diff --git a/packages/graphile-build-pg/src/index.js b/packages/graphile-build-pg/src/index.js index fbdacac52..7d6f2777e 100644 --- a/packages/graphile-build-pg/src/index.js +++ b/packages/graphile-build-pg/src/index.js @@ -17,9 +17,7 @@ import PgColumnDeprecationPlugin from "./plugins/PgColumnDeprecationPlugin"; import PgForwardRelationPlugin from "./plugins/PgForwardRelationPlugin"; import PgBackwardRelationPlugin from "./plugins/PgBackwardRelationPlugin"; import PgRowByUniqueConstraint from "./plugins/PgRowByUniqueConstraint"; -import PgComputedColumnsPlugin, { - getComputedColumnDetails, -} from "./plugins/PgComputedColumnsPlugin"; +import PgComputedColumnsPlugin from "./plugins/PgComputedColumnsPlugin"; import PgQueryProceduresPlugin from "./plugins/PgQueryProceduresPlugin"; import PgOrderAllColumnsPlugin from "./plugins/PgOrderAllColumnsPlugin"; import PgOrderComputedColumnsPlugin from "./plugins/PgOrderComputedColumnsPlugin"; @@ -83,7 +81,7 @@ export const defaultPlugins = [ PgMutationPayloadEdgePlugin, ]; -export { inflections, getComputedColumnDetails }; +export { inflections }; // TypeScript compatibility export { PgEntityKind }; diff --git a/packages/graphile-build-pg/src/plugins/PgBasicsPlugin.js b/packages/graphile-build-pg/src/plugins/PgBasicsPlugin.js index fd0689b3f..d6b63c25b 100644 --- a/packages/graphile-build-pg/src/plugins/PgBasicsPlugin.js +++ b/packages/graphile-build-pg/src/plugins/PgBasicsPlugin.js @@ -25,7 +25,8 @@ import baseOmit, { FILTER, EXECUTE, } from "../omit"; -import makeProcField from "./makeProcField"; +import makeProcField, { procFieldDetails } from "./makeProcField"; +import { getComputedColumnDetails } from "./PgComputedColumnsPlugin"; import parseIdentifier from "../parseIdentifier"; import viaTemporaryTable from "./viaTemporaryTable"; import chalk from "chalk"; @@ -349,6 +350,8 @@ export default (function PgBasicsPlugin( pgAddStartEndCursor: addStartEndCursor, pgOmit, pgMakeProcField: makeProcField, + pgProcFieldDetails: procFieldDetails, + pgGetComputedColumnDetails: getComputedColumnDetails, pgParseIdentifier: parseIdentifier, pgViaTemporaryTable: viaTemporaryTable, describePgEntity, diff --git a/packages/graphile-build-pg/src/plugins/PgIntrospectionPlugin.d.ts b/packages/graphile-build-pg/src/plugins/PgIntrospectionPlugin.d.ts index cb94b3982..9d4939393 100644 --- a/packages/graphile-build-pg/src/plugins/PgIntrospectionPlugin.d.ts +++ b/packages/graphile-build-pg/src/plugins/PgIntrospectionPlugin.d.ts @@ -14,8 +14,8 @@ export interface PgNamespace { kind: PgEntityKind.NAMESPACE; id: string; name: string; - comment: string | void; - description: string | void; + comment: string | undefined; + description: string | undefined; tags: { [tag: string]: true | string | Array }; } @@ -23,8 +23,8 @@ export interface PgProc { kind: PgEntityKind.PROCEDURE; id: string; name: string; - comment: string | void; - description: string | void; + comment: string | undefined; + description: string | undefined; namespaceId: string; namespaceName: string; isStrict: boolean; @@ -47,8 +47,8 @@ export interface PgClass { kind: PgEntityKind.CLASS; id: string; name: string; - comment: string | void; - description: string | void; + comment: string | undefined; + description: string | undefined; classKind: string; namespaceId: string; namespaceName: string; @@ -64,7 +64,7 @@ export interface PgClass { attributes: Array; constraints: Array; foreignConstraints: Array; - primaryKeyConstraint: PgConstraint | void; + primaryKeyConstraint: PgConstraint | undefined; aclSelectable: boolean; aclInsertable: boolean; aclUpdatable: boolean; @@ -76,27 +76,27 @@ export interface PgType { kind: PgEntityKind.TYPE; id: string; name: string; - comment: string | void; - description: string | void; + comment: string | undefined; + description: string | undefined; namespaceId: string; namespaceName: string; type: string; category: string; domainIsNotNull: boolean; - arrayItemTypeId: string | void; - arrayItemType: PgType | void; - arrayType: PgType | void; - typeLength: number | void; + arrayItemTypeId: string | undefined; + arrayItemType: PgType | undefined; + arrayType: PgType | undefined; + typeLength: number | undefined; isPgArray: boolean; - classId: string | void; - class: PgClass | void; - domainBaseTypeId: string | void; - domainBaseType: PgType | void; - domainTypeModifier: number | void; + classId: string | undefined; + class: PgClass | undefined; + domainBaseTypeId: string | undefined; + domainBaseType: PgType | undefined; + domainTypeModifier: number | undefined; domainHasDefault: boolean; - enumVariants: string[] | void; - enumDescriptions: string[] | void; - rangeSubTypeId: string | void; + enumVariants: string[] | undefined; + enumDescriptions: string[] | undefined; + rangeSubTypeId: string | undefined; tags: { [tag: string]: true | string | Array }; isFake?: boolean; } @@ -106,8 +106,8 @@ export interface PgAttribute { classId: string; num: number; name: string; - comment: string | void; - description: string | void; + comment: string | undefined; + description: string | undefined; typeId: string; typeModifier: number; isNotNull: boolean; @@ -120,8 +120,8 @@ export interface PgAttribute { aclSelectable: boolean; aclInsertable: boolean; aclUpdatable: boolean; - isIndexed: boolean | void; - isUnique: boolean | void; + isIndexed: boolean | undefined; + isUnique: boolean | undefined; columnLevelSelectGrant: boolean; } @@ -132,16 +132,16 @@ export interface PgConstraint { type: string; classId: string; class: PgClass; - foreignClassId: string | void; - foreignClass: PgClass | void; - comment: string | void; - description: string | void; + foreignClassId: string | undefined; + foreignClass: PgClass | undefined; + comment: string | undefined; + description: string | undefined; keyAttributeNums: Array; keyAttributes: Array; foreignKeyAttributeNums: Array; foreignKeyAttributes: Array; namespace: PgNamespace; - isIndexed: boolean | void; + isIndexed: boolean | undefined; tags: { [tag: string]: true | string | Array }; } @@ -154,8 +154,8 @@ export interface PgExtension { relocatable: boolean; version: string; configurationClassIds?: Array; - comment: string | void; - description: string | void; + comment: string | undefined; + description: string | undefined; tags: { [tag: string]: true | string | Array }; } @@ -171,9 +171,9 @@ export interface PgIndex { isPrimary: boolean; isPartial: boolean; attributeNums: Array; - attributePropertiesAsc: Array | void; - attributePropertiesNullsFirst: Array | void; - description: string | void; + attributePropertiesAsc: Array | undefined; + attributePropertiesNullsFirst: Array | undefined; + description: string | undefined; tags: { [tag: string]: true | string | Array }; } diff --git a/packages/graphile-build-pg/src/plugins/introspectionQuery.js b/packages/graphile-build-pg/src/plugins/introspectionQuery.js index c8a6d00f8..99c581d9d 100644 --- a/packages/graphile-build-pg/src/plugins/introspectionQuery.js +++ b/packages/graphile-build-pg/src/plugins/introspectionQuery.js @@ -30,7 +30,7 @@ function makeIntrospectionQuery( -- - \`$1\`: An array of strings that represent the namespaces we are introspecting. -- - \`$2\`: set true to include functions/tables/etc that come from extensions with - ${!pgIgnoreRBAC ? "recursive" : ""} accessible_roles(_oid) as ( + ${!pgIgnoreRBAC ? "recursive" : ""} accessible_roles as ( select oid _oid, pg_roles.* from pg_roles where rolname = current_user diff --git a/packages/graphile-build-pg/src/plugins/makeProcField.d.ts b/packages/graphile-build-pg/src/plugins/makeProcField.d.ts new file mode 100644 index 000000000..d4fc9d90d --- /dev/null +++ b/packages/graphile-build-pg/src/plugins/makeProcField.d.ts @@ -0,0 +1,26 @@ +import { PgType, PgProc } from "./PgIntrospectionPlugin"; +import { GraphQLInputType } from "graphql"; +import { Build } from "graphile-build"; +import { SQL } from "../QueryBuilder"; + +export function procFieldDetails( + proc: PgProc, + build: Build, + options: { + computed?: boolean; + isMutation?: boolean; + } +): { + inputs: { + [name: string]: { + type: GraphQLInputType; + description?: string; + }; + }; + makeSqlFunctionCall: ( + args: any, + options: { implicitArgs?: any[]; unnest?: boolean } + ) => SQL; + outputArgNames: string[]; + outputArgTypes: PgType[]; +}; diff --git a/packages/graphile-build-pg/src/plugins/makeProcField.js b/packages/graphile-build-pg/src/plugins/makeProcField.js index b145c27de..cd071dacd 100644 --- a/packages/graphile-build-pg/src/plugins/makeProcField.js +++ b/packages/graphile-build-pg/src/plugins/makeProcField.js @@ -8,6 +8,22 @@ import type { SQL } from "pg-sql2"; import debugSql from "./debugSql"; import chalk from "chalk"; +type ProcFieldOptions = { + fieldWithHooks: FieldWithHooksFunction, + computed?: boolean, + isMutation?: boolean, + isRootQuery?: boolean, + forceList?: boolean, + aggregateWrapper?: null | ((sql: SQL) => SQL), + description?: string, + pgTypeAndModifierModifier?: + | null + | (( + pgType: PgType, + pgTypeModifier: null | string | number + ) => [PgType, null | string | number]), +}; + const firstValue = obj => { let firstKey; for (const k in obj) { @@ -18,75 +34,31 @@ const firstValue = obj => { return obj[firstKey]; }; -export default function makeProcField( - fieldName: string, +export function procFieldDetails( proc: PgProc, build: {| ...Build |}, - { - fieldWithHooks, - computed = false, - isMutation = false, - isRootQuery = false, - forceList = false, - aggregateWrapper = null, - description: overrideDescription = null, - pgTypeAndModifierModifier = null, - }: { - fieldWithHooks: FieldWithHooksFunction, + options: { computed?: boolean, isMutation?: boolean, - isRootQuery?: boolean, - forceList?: boolean, - aggregateWrapper?: null | ((sql: SQL) => SQL), - description?: string, - pgTypeAndModifierModifier?: - | null - | (( - pgType: PgType, - pgTypeModifier: null | string | number - ) => [PgType, null | string | number]), } ) { + const { computed = false, isMutation = false } = options; const { pgIntrospectionResultsByKind: introspectionResultsByKind, - pgGetGqlTypeByTypeIdAndModifier, pgGetGqlInputTypeByTypeIdAndModifier, - getTypeByName, pgSql: sql, - parseResolveInfo, - getSafeAliasFromResolveInfo, - getSafeAliasFromAlias, gql2pg, - pg2gql, - newWithHooks, pgStrictFunctions: strictFunctions, - pgTweakFragmentForTypeAndModifier, - graphql: { - GraphQLNonNull, - GraphQLList, - GraphQLString, - GraphQLObjectType, - GraphQLInputObjectType, - getNamedType, - isCompositeType, - }, + graphql: { GraphQLNonNull }, inflection, - pgQueryFromResolveData: queryFromResolveData, - pgAddStartEndCursor: addStartEndCursor, - pgViaTemporaryTable: viaTemporaryTable, describePgEntity, sqlCommentByAddingTags, - pgField, - options: { - subscriptions = false, - pgForbidSetofFunctionsToReturnNull = false, - }, - pgPrepareAndRun, } = build; if (computed && isMutation) { throw new Error("Mutation procedure cannot be computed"); } + const sliceAmount = computed ? 1 : 0; const argNames = proc.argTypeIds.reduce((prev, _, idx) => { if ( @@ -128,7 +100,7 @@ export default function makeProcField( return prev; }, []); const requiredArgCount = Math.max(0, argNames.length - proc.argDefaultsNum); - const variantFromName = (name, _type) => { + const variantFromName = name => { if (name.match(/(_p|P)atch$/)) { return "patch"; } @@ -146,7 +118,7 @@ export default function makeProcField( const argGqlTypes = argTypes.map((type, idx) => { // TODO: PG10 doesn't support the equivalent of pg_attribute.atttypemod on function return values, but maybe a later version might const variant = - variantFromTags(proc.tags, idx) || variantFromName(argNames[idx], type); + variantFromTags(proc.tags, idx) || variantFromName(argNames[idx]); const Type = pgGetGqlInputTypeByTypeIdAndModifier(type.id, variant); if (!Type) { const hint = type.class @@ -173,6 +145,120 @@ export default function makeProcField( return new GraphQLNonNull(Type); } }); + // This wants to be compatible with both being field arguments and being + // input object fields (e.g. for the aggregates plugin). + const inputs = argNames.reduce((memo, argName, argIndex) => { + const gqlArgName = inflection.argument(argName, argIndex); + memo[gqlArgName] = { + type: argGqlTypes[argIndex], + }; + return memo; + }, {}); + + function makeSqlFunctionCall( + rawArgs = {}, + { implicitArgs = [], unnest = false } = {} + ): SQL { + const args = isMutation ? rawArgs.input : rawArgs; + const sqlArgValues = []; + let haveNames = true; + for (let argIndex = argNames.length - 1; argIndex >= 0; argIndex--) { + const argName = argNames[argIndex]; + const gqlArgName = inflection.argument(argName, argIndex); + const value = args[gqlArgName]; + const variant = + variantFromTags(proc.tags, argIndex) || + variantFromName(argNames[argIndex]); + + const sqlValue = gql2pg(value, argTypes[argIndex], variant); + + if (argIndex + 1 > requiredArgCount && haveNames && value == null) { + // No need to pass argument to function + continue; + } else if (argIndex + 1 > requiredArgCount && haveNames) { + const sqlArgName = argName ? sql.identifier(argName) : null; + if (sqlArgName) { + sqlArgValues.unshift(sql.fragment`${sqlArgName} := ${sqlValue}`); + } else { + haveNames = false; + sqlArgValues.unshift(sqlValue); + } + } else { + sqlArgValues.unshift(sqlValue); + } + } + const functionCall = sql.fragment`${sql.identifier( + proc.namespace.name, + proc.name + )}(${sql.join([...implicitArgs, ...sqlArgValues], ", ")})`; + return unnest ? sql.fragment`unnest(${functionCall})` : functionCall; + } + + return { + inputs, + makeSqlFunctionCall, + outputArgNames, + outputArgTypes, + }; +} + +export default function makeProcField( + fieldName: string, + proc: PgProc, + build: {| ...Build |}, + options: ProcFieldOptions +) { + const { + fieldWithHooks, + computed = false, + isMutation = false, + isRootQuery = false, + forceList = false, + aggregateWrapper = null, + description: overrideDescription = null, + pgTypeAndModifierModifier = null, + } = options; + const { + pgIntrospectionResultsByKind: introspectionResultsByKind, + pgGetGqlTypeByTypeIdAndModifier, + getTypeByName, + pgSql: sql, + parseResolveInfo, + getSafeAliasFromResolveInfo, + getSafeAliasFromAlias, + pg2gql, + newWithHooks, + pgTweakFragmentForTypeAndModifier, + graphql: { + GraphQLNonNull, + GraphQLList, + GraphQLString, + GraphQLObjectType, + GraphQLInputObjectType, + getNamedType, + isCompositeType, + }, + inflection, + pgQueryFromResolveData: queryFromResolveData, + pgAddStartEndCursor: addStartEndCursor, + pgViaTemporaryTable: viaTemporaryTable, + describePgEntity, + sqlCommentByAddingTags, + pgField, + options: { + subscriptions = false, + pgForbidSetofFunctionsToReturnNull = false, + }, + pgPrepareAndRun, + } = build; + + const { + inputs, + makeSqlFunctionCall, + outputArgNames, + outputArgTypes, + } = procFieldDetails(proc, build, options); + let args = inputs; /** * This is the return type the function claims to have; we @@ -340,48 +426,6 @@ export default function makeProcField( }; }); } - function makeSqlFunctionCall( - parsedResolveInfoFragment, - ReturnType, - { implicitArgs = [] } = {} - ): SQL { - const { args: rawArgs = {} } = parsedResolveInfoFragment; - const args = isMutation ? rawArgs.input : rawArgs; - const sqlArgValues = []; - let haveNames = true; - for (let argIndex = argNames.length - 1; argIndex >= 0; argIndex--) { - const argName = argNames[argIndex]; - const gqlArgName = inflection.argument(argName, argIndex); - const value = args[gqlArgName]; - const variant = - variantFromTags(proc.tags, argIndex) || - variantFromName(argNames[argIndex], type); - - const sqlValue = gql2pg(value, argTypes[argIndex], variant); - - if (argIndex + 1 > requiredArgCount && haveNames && value == null) { - // No need to pass argument to function - continue; - } else if (argIndex + 1 > requiredArgCount && haveNames) { - const sqlArgName = argName ? sql.identifier(argName) : null; - if (sqlArgName) { - sqlArgValues.unshift(sql.fragment`${sqlArgName} := ${sqlValue}`); - } else { - haveNames = false; - sqlArgValues.unshift(sqlValue); - } - } else { - sqlArgValues.unshift(sqlValue); - } - } - const functionCall = sql.fragment`${sql.identifier( - proc.namespace.name, - proc.name - )}(${sql.join([...implicitArgs, ...sqlArgValues], ", ")})`; - return rawReturnType.isPgArray - ? sql.fragment`unnest(${functionCall})` - : functionCall; - } function makeQuery( parsedResolveInfoFragment, ReturnType, @@ -467,10 +511,10 @@ export default function makeProcField( const parentTableAlias = queryBuilder.getTableAlias(); const functionAlias = sql.identifier(Symbol()); const sqlFunctionCall = makeSqlFunctionCall( - parsedResolveInfoFragment, - ReturnType, + parsedResolveInfoFragment.args, { implicitArgs: [parentTableAlias], + unnest: rawReturnType.isPgArray, } ); if (aggregateWrapper) { @@ -493,13 +537,6 @@ export default function makeProcField( let ReturnType = type; let PayloadType; - let args = argNames.reduce((memo, argName, argIndex) => { - const gqlArgName = inflection.argument(argName, argIndex); - memo[gqlArgName] = { - type: argGqlTypes[argIndex], - }; - return memo; - }, {}); if (isMutation) { const resultFieldName = inflection.functionMutationResultFieldName( proc, @@ -696,9 +733,10 @@ export default function makeProcField( parsedResolveInfoFragment.args = args; // Allow overriding via makeWrapResolversPlugin const functionAlias = sql.identifier(Symbol()); const sqlFunctionCall = makeSqlFunctionCall( - parsedResolveInfoFragment, - resolveInfo.returnType, - {} + parsedResolveInfoFragment.args, + { + unnest: rawReturnType.isPgArray, + } ); let queryResultRows; diff --git a/packages/graphile-utils/src/makeAddPgTableConditionPlugin.ts b/packages/graphile-utils/src/makeAddPgTableConditionPlugin.ts index 110025bd1..afa4f3e68 100644 --- a/packages/graphile-utils/src/makeAddPgTableConditionPlugin.ts +++ b/packages/graphile-utils/src/makeAddPgTableConditionPlugin.ts @@ -16,7 +16,7 @@ export default function makeAddPgTableConditionPlugin( sqlTableAlias: SQL; }, build: Build - ) => SQL | null | void + ) => SQL | null | undefined ) { const displayName = `makeAddPgTableConditionPlugin__${schemaName}__${tableName}__${conditionFieldName}`; const plugin: Plugin = builder => { diff --git a/packages/graphile-utils/src/makeExtendSchemaPlugin.ts b/packages/graphile-utils/src/makeExtendSchemaPlugin.ts index f45beb88a..391895a97 100644 --- a/packages/graphile-utils/src/makeExtendSchemaPlugin.ts +++ b/packages/graphile-utils/src/makeExtendSchemaPlugin.ts @@ -588,7 +588,7 @@ export default function makeExtendSchemaPlugin( throw new Error("Could not extract name from AST"); } - function getDescription(desc: StringValueNode | void) { + function getDescription(desc: StringValueNode | undefined) { if (!desc) { return null; } else if (desc.kind === "StringValue") { @@ -690,7 +690,7 @@ export default function makeExtendSchemaPlugin( } function getDirectives( - directives: ReadonlyArray | void + directives: ReadonlyArray | undefined ): DirectiveMap { return (directives || []).reduce((directivesList, directive) => { if (directive.kind === "Directive") { @@ -731,7 +731,7 @@ export default function makeExtendSchemaPlugin( } function getArguments( - args: ReadonlyArray | void, + args: ReadonlyArray | undefined, build: Build ) { if (args && args.length) { @@ -762,7 +762,7 @@ export default function makeExtendSchemaPlugin( function getFields( SelfGeneric: TSource, - fields: ReadonlyArray | void, + fields: ReadonlyArray | undefined, resolvers: Resolvers, { fieldWithHooks, @@ -1140,7 +1140,7 @@ export default function makeExtendSchemaPlugin( function getInputFields( _Self: TSource, - fields: ReadonlyArray | void, + fields: ReadonlyArray | undefined, build: Build ) { if (fields && fields.length) { diff --git a/packages/graphql-parse-resolve-info/src/index.ts b/packages/graphql-parse-resolve-info/src/index.ts index e9068441f..acbc60fd5 100644 --- a/packages/graphql-parse-resolve-info/src/index.ts +++ b/packages/graphql-parse-resolve-info/src/index.ts @@ -103,7 +103,7 @@ export interface ParseOptions { export function parseResolveInfo( resolveInfo: GraphQLResolveInfo, options: ParseOptions = {} -): ResolveTree | FieldsByTypeName | null | void { +): ResolveTree | FieldsByTypeName | null | undefined { const fieldNodes: ReadonlyArray = // @ts-ignore Property 'fieldASTs' does not exist on type 'GraphQLResolveInfo'. resolveInfo.fieldNodes || resolveInfo.fieldASTs; diff --git a/packages/pg-pubsub/src/PgGenericSubscriptionPlugin.ts b/packages/pg-pubsub/src/PgGenericSubscriptionPlugin.ts index 9bc07b2d2..6f825d1d5 100644 --- a/packages/pg-pubsub/src/PgGenericSubscriptionPlugin.ts +++ b/packages/pg-pubsub/src/PgGenericSubscriptionPlugin.ts @@ -147,7 +147,7 @@ const PgGenericSubscriptionPlugin: Plugin = function ( const { pgClient } = _context; const topic = (pgSubscriptionPrefix || "") + args.topic; // Check they're allowed - let unsubscribeTopic: string | void; + let unsubscribeTopic: string | undefined; if (parsedFunctionParts) { const { text, values } = sql.compile( sql.query`select unsubscribe_topic from ${sql.identifier( diff --git a/packages/pg-sql2/src/index.ts b/packages/pg-sql2/src/index.ts index c22933ed2..a8970ede5 100644 --- a/packages/pg-sql2/src/index.ts +++ b/packages/pg-sql2/src/index.ts @@ -329,4 +329,11 @@ export function escapeSqlIdentifier(str: string) { export const blank = query``; -export { query as fragment, nullNode as null }; +export { + query as fragment, + // sql.null deprecated; use `sql.NULL` instead. + nullNode as null, + nullNode as NULL, + trueNode as TRUE, + falseNode as FALSE, +}; diff --git a/packages/subscriptions-lds/src/PgLDSSourcePlugin.ts b/packages/subscriptions-lds/src/PgLDSSourcePlugin.ts index ffd314268..239f76196 100644 --- a/packages/subscriptions-lds/src/PgLDSSourcePlugin.ts +++ b/packages/subscriptions-lds/src/PgLDSSourcePlugin.ts @@ -27,7 +27,7 @@ export class LDSLiveSource { private reconnecting: boolean; private live: boolean; private subscriptions: { - [topic: string]: Array<[SubscriptionCallback, Predicate | void]>; + [topic: string]: Array<[SubscriptionCallback, Predicate | undefined]>; }; private ws: WebSocket | null; private sleepDuration?: number; @@ -170,12 +170,15 @@ export class LDSLiveSource { private sub( topic: string, cb: SubscriptionCallback, - predicate?: Predicate | void + predicate?: Predicate | undefined ) { if (!this.live) { return null; } - const entry: [SubscriptionCallback, Predicate | void] = [cb, predicate]; + const entry: [SubscriptionCallback, Predicate | undefined] = [ + cb, + predicate, + ]; if (!this.subscriptions[topic]) { this.subscriptions[topic] = []; }