build: use strict null checks part 1

This commit is contained in:
Kamil Myśliwiec
2024-11-26 12:46:59 +01:00
parent 38367e8e88
commit 10fdf16c47
51 changed files with 413 additions and 304 deletions

View File

@@ -128,8 +128,8 @@ export class Module {
}
get entryProviders(): Array<InstanceWrapper<Injectable>> {
return Array.from(this._entryProviderKeys).map(token =>
this.providers.get(token),
return Array.from(this._entryProviderKeys).map(
token => this.providers.get(token)!,
);
}
@@ -379,7 +379,7 @@ export class Module {
new InstanceWrapper({
token: providerToken,
name: (providerToken as Function)?.name || providerToken,
metatype: null,
metatype: null!,
instance: value,
isResolved: true,
async: value instanceof Promise,
@@ -497,7 +497,7 @@ export class Module {
token: controller,
name: controller.name,
metatype: controller,
instance: null,
instance: null!,
isResolved: false,
scope: getClassScope(controller),
durable: isDurable(controller),
@@ -532,11 +532,11 @@ export class Module {
if (options.isProvider && this.hasProvider(toReplace)) {
const originalProvider = this._providers.get(toReplace);
return originalProvider.mergeWith({ provide: toReplace, ...options });
return originalProvider!.mergeWith({ provide: toReplace, ...options });
} else if (!options.isProvider && this.hasInjectable(toReplace)) {
const originalInjectable = this._injectables.get(toReplace);
return originalInjectable.mergeWith({
return originalInjectable!.mergeWith({
provide: toReplace,
...options,
});

View File

@@ -91,7 +91,7 @@ export class GraphInspector {
}
public insertAttachedEnhancer(wrapper: InstanceWrapper) {
const existingNode = this.graph.getNodeById(wrapper.id);
const existingNode = this.graph.getNodeById(wrapper.id)!;
existingNode.metadata.global = true;
this.graph.insertAttachedEnhancer(existingNode.id);
@@ -123,12 +123,12 @@ export class GraphInspector {
sourceModuleName: moduleRef.name,
durable: wrapper.isDependencyTreeDurable(),
static: wrapper.isDependencyTreeStatic(),
scope: wrapper.scope,
scope: wrapper.scope!,
transient: wrapper.isTransient,
exported: moduleRef.exports.has(wrapper.token),
token: wrapper.token,
subtype: wrapper.subtype,
initTime: wrapper.initTime,
initTime: wrapper.initTime!,
},
});
}
@@ -168,7 +168,7 @@ export class GraphInspector {
const moduleRef = this.container.getModuleByKey(entry.moduleToken);
const sourceInstanceWrapper =
moduleRef.controllers.get(entry.classRef) ??
moduleRef.providers.get(entry.classRef);
moduleRef.providers.get(entry.classRef)!;
const existingSourceNode = this.graph.getNodeById(
sourceInstanceWrapper.id,
) as ClassNode;
@@ -190,7 +190,7 @@ export class GraphInspector {
});
} else {
const name =
entry.enhancerRef.constructor?.name ??
entry.enhancerRef!.constructor?.name ??
(entry.enhancerRef as Function).name;
enhancers.push({
@@ -219,7 +219,7 @@ export class GraphInspector {
targetClassName: target.name,
sourceClassToken: source.token,
targetClassToken: target.token,
targetModuleName: target.host?.name,
targetModuleName: target.host?.name!,
keyOrIndex,
injectionType,
},

View File

@@ -41,19 +41,19 @@ export class InterceptorsContextCreator extends ContextCreator {
inquirerId?: string,
): R {
if (isEmpty(metadata)) {
return [] as R;
return [] as any[] as R;
}
return iterate(metadata)
.filter(
interceptor =>
interceptor && (interceptor.name || interceptor.intercept),
)
.map(interceptor =>
this.getInterceptorInstance(interceptor, contextId, inquirerId),
.map(
interceptor =>
this.getInterceptorInstance(interceptor, contextId, inquirerId)!,
)
.filter(
(interceptor: NestInterceptor) =>
interceptor && isFunction(interceptor.intercept),
.filter((interceptor: NestInterceptor) =>
interceptor ? isFunction(interceptor.intercept) : false,
)
.toArray() as R;
}
@@ -63,7 +63,7 @@ export class InterceptorsContextCreator extends ContextCreator {
contextId = STATIC_CONTEXT,
inquirerId?: string,
): NestInterceptor | null {
const isObject = (metatype as NestInterceptor).intercept;
const isObject = !!(metatype as NestInterceptor).intercept;
if (isObject) {
return metatype as NestInterceptor;
}
@@ -99,7 +99,7 @@ export class InterceptorsContextCreator extends ContextCreator {
inquirerId?: string,
): T {
if (!this.config) {
return [] as T;
return [] as unknown[] as T;
}
const globalInterceptors = this.config.getGlobalInterceptors() as T;
if (contextId === STATIC_CONTEXT && !inquirerId) {

View File

@@ -34,7 +34,10 @@ export class MetadataScanner {
visitedNames.set(property, true);
// reason: https://github.com/nestjs/nest/pull/10821#issuecomment-1411916533
const descriptor = Object.getOwnPropertyDescriptor(prototype, property);
const descriptor = Object.getOwnPropertyDescriptor(
prototype,
property,
)!;
if (
descriptor.set ||

View File

@@ -338,8 +338,8 @@ export class MiddlewareModule<
}
private getContextId(request: unknown, isTreeDurable: boolean): ContextId {
const contextId = ContextIdFactory.getByRequest(request);
if (!request[REQUEST_CONTEXT_ID]) {
const contextId = ContextIdFactory.getByRequest(request!);
if (!request![REQUEST_CONTEXT_ID]) {
Object.defineProperty(request, REQUEST_CONTEXT_ID, {
value: contextId,
enumerable: false,

View File

@@ -112,9 +112,9 @@ export function isMiddlewareRouteExcluded(
if (excludedRoutes.length <= 0) {
return false;
}
const reqMethod = httpAdapter.getRequestMethod(req);
const originalUrl = httpAdapter.getRequestUrl(req);
const queryParamsIndex = originalUrl && originalUrl.indexOf('?');
const reqMethod = httpAdapter.getRequestMethod?.(req)!;
const originalUrl = httpAdapter.getRequestUrl?.(req)!;
const queryParamsIndex = originalUrl ? originalUrl.indexOf('?') : -1;
const pathname =
queryParamsIndex >= 0
? originalUrl.slice(0, queryParamsIndex)

View File

@@ -26,15 +26,15 @@ import { NestContainer } from '../injector/container';
import { Injector } from '../injector/injector';
import { ContextId, InstanceWrapper } from '../injector/instance-wrapper';
import { Module } from '../injector/module';
import {
InterceptorsConsumer,
InterceptorsContextCreator,
} from '../interceptors';
import { GraphInspector } from '../inspector/graph-inspector';
import {
Entrypoint,
HttpEntrypointMetadata,
} from '../inspector/interfaces/entrypoint.interface';
import {
InterceptorsConsumer,
InterceptorsContextCreator,
} from '../interceptors';
import { MetadataScanner } from '../metadata-scanner';
import { PipesConsumer, PipesContextCreator } from '../pipes';
import { ExceptionsFilter } from './interfaces/exceptions-filter.interface';

View File

@@ -78,7 +78,7 @@ export class RouterModule {
private updateTargetModulesCache(moduleCtor: Type<unknown>) {
let moduleClassSet: WeakSet<ModuleClass>;
if (targetModulesByContainer.has(this.modulesContainer)) {
moduleClassSet = targetModulesByContainer.get(this.modulesContainer);
moduleClassSet = targetModulesByContainer.get(this.modulesContainer)!;
} else {
moduleClassSet = new WeakSet<ModuleClass>();
targetModulesByContainer.set(this.modulesContainer, moduleClassSet);

View File

@@ -1,8 +1,12 @@
import { normalizePath, isString } from '@nestjs/common/utils/shared.utils';
import { Type } from '@nestjs/common';
import { isString, normalizePath } from '@nestjs/common/utils/shared.utils';
import { Routes } from '../interfaces/routes.interface';
export function flattenRoutePaths(routes: Routes) {
const result = [];
const result: Array<{
module: Type;
path: string;
}> = [];
routes.forEach(item => {
if (item.module && item.path) {
result.push({ module: item.module, path: item.path });
@@ -15,7 +19,7 @@ export function flattenRoutePaths(routes: Routes) {
normalizePath(item.path) + normalizePath(child.path),
);
} else {
result.push({ path: item.path, module: child });
result.push({ path: item.path, module: child as any as Type });
}
});
result.push(...flattenRoutePaths(childrenRef));

View File

@@ -138,7 +138,7 @@ export class DependenciesScanner {
...((moduleDefinition as DynamicModule).imports || []),
];
let registeredModuleRefs = [];
let registeredModuleRefs: Module[] = [];
for (const [index, innerModule] of modules.entries()) {
// In case of a circular dependency (ES module system), JavaScript will resolve the type to `undefined`.
if (innerModule === undefined) {
@@ -152,7 +152,7 @@ export class DependenciesScanner {
}
const moduleRefs = await this.scanForModules({
moduleDefinition: innerModule,
scope: [].concat(scope, moduleDefinition),
scope: ([] as Array<Type>).concat(scope, moduleDefinition as Type),
ctxRegistry,
overrides,
lazy,
@@ -215,7 +215,7 @@ export class DependenciesScanner {
...this.container.getDynamicMetadataByToken(
token,
MODULE_METADATA.IMPORTS as 'imports',
),
)!,
];
for (const related of modules) {
await this.insertImport(related, token, context);
@@ -228,7 +228,7 @@ export class DependenciesScanner {
...this.container.getDynamicMetadataByToken(
token,
MODULE_METADATA.PROVIDERS as 'providers',
),
)!,
];
providers.forEach(provider => {
this.insertProvider(provider, token);
@@ -242,7 +242,7 @@ export class DependenciesScanner {
...this.container.getDynamicMetadataByToken(
token,
MODULE_METADATA.CONTROLLERS as 'controllers',
),
)!,
];
controllers.forEach(item => {
this.insertController(item, token);
@@ -267,7 +267,7 @@ export class DependenciesScanner {
...this.container.getDynamicMetadataByToken(
token,
MODULE_METADATA.EXPORTS as 'exports',
),
)!,
];
exports.forEach(exportedProvider =>
this.insertExportedProvider(exportedProvider, token),
@@ -285,19 +285,25 @@ export class DependenciesScanner {
);
const methodInjectables = this.metadataScanner
.getAllMethodNames(component.prototype)
.reduce((acc, method) => {
const methodInjectable = this.reflectKeyMetadata(
component,
metadataKey,
method,
);
.reduce(
(acc, method) => {
const methodInjectable = this.reflectKeyMetadata(
component,
metadataKey,
method,
);
if (methodInjectable) {
acc.push(methodInjectable);
}
if (methodInjectable) {
acc.push(methodInjectable);
}
return acc;
}, []);
return acc;
},
[] as Array<{
methodKey: string;
metadata: Type<Injectable>[];
}>,
);
controllerInjectables.forEach(injectable =>
this.insertInjectable(
@@ -308,13 +314,13 @@ export class DependenciesScanner {
),
);
methodInjectables.forEach(methodInjectable => {
methodInjectable.metadata.forEach(injectable =>
methodInjectable.metadata!.forEach(injectable =>
this.insertInjectable(
injectable,
token,
component,
ENHANCER_KEY_TO_SUBTYPE_MAP[metadataKey],
methodInjectable.methodKey,
methodInjectable.methodKey!,
),
);
});
@@ -392,7 +398,7 @@ export class DependenciesScanner {
const calculateDistance = (
moduleRef: Module,
distance = 1,
modulesStack = [],
modulesStack: Module[] = [],
) => {
const localModulesStack = [...modulesStack];
if (!moduleRef || localModulesStack.includes(moduleRef)) {
@@ -412,7 +418,7 @@ export class DependenciesScanner {
};
const rootModule = modulesGenerator.next().value;
calculateDistance(rootModule);
calculateDistance(rootModule!);
}
public async insertImport(related: any, token: string, context: string) {
@@ -478,7 +484,7 @@ export class DependenciesScanner {
const factoryOrClassProvider = newProvider as
| FactoryProvider
| ClassProvider;
if (this.isRequestOrTransient(factoryOrClassProvider.scope)) {
if (this.isRequestOrTransient(factoryOrClassProvider.scope!)) {
return this.container.addInjectable(newProvider, token, enhancerSubtype);
}
this.container.addProvider(newProvider, token, enhancerSubtype);
@@ -629,10 +635,10 @@ export class DependenciesScanner {
*/
public addScopedEnhancersMetadata() {
iterate(this.applicationProvidersApplyMap)
.filter(wrapper => this.isRequestOrTransient(wrapper.scope))
.filter(wrapper => this.isRequestOrTransient(wrapper.scope!))
.forEach(({ moduleKey, providerKey }) => {
const modulesContainer = this.container.getModules();
const { injectables } = modulesContainer.get(moduleKey);
const { injectables } = modulesContainer.get(moduleKey)!;
const instanceWrapper = injectables.get(providerKey);
const iterableIterator = modulesContainer.values();
@@ -644,7 +650,7 @@ export class DependenciesScanner {
)
.flatten()
.forEach(controllerOrEntryProvider =>
controllerOrEntryProvider.addEnhancerMetadata(instanceWrapper),
controllerOrEntryProvider.addEnhancerMetadata(instanceWrapper!),
);
});
}
@@ -659,7 +665,7 @@ export class DependenciesScanner {
collectionKey: 'providers' | 'injectables',
) => {
const modules = this.container.getModules();
const collection = modules.get(moduleKey)[collectionKey];
const collection = modules.get(moduleKey)![collectionKey];
return collection.get(providerKey);
};
@@ -667,12 +673,12 @@ export class DependenciesScanner {
this.applicationProvidersApplyMap.forEach(
({ moduleKey, providerKey, type, scope }) => {
let instanceWrapper: InstanceWrapper;
if (this.isRequestOrTransient(scope)) {
if (this.isRequestOrTransient(scope!)) {
instanceWrapper = getInstanceWrapper(
moduleKey,
providerKey,
'injectables',
);
)!;
this.graphInspector.insertAttachedEnhancer(instanceWrapper);
return applyRequestProvidersMap[type as string](instanceWrapper);
@@ -681,7 +687,7 @@ export class DependenciesScanner {
moduleKey,
providerKey,
'providers',
);
)!;
this.graphInspector.insertAttachedEnhancer(instanceWrapper);
applyProvidersMap[type as string](instanceWrapper.instance);
},

View File

@@ -64,7 +64,7 @@ export class Reflector {
const value = options.transform
? options.transform(metadataValue)
: metadataValue;
SetMetadata(metadataKey, value ?? {})(target, key, descriptor);
SetMetadata(metadataKey, value ?? {})(target, key!, descriptor);
};
decoratorFn.KEY = metadataKey;
@@ -256,7 +256,7 @@ export class Reflector {
public getAllAndOverride<TResult = any, TKey = any>(
metadataKeyOrDecorator: TKey,
targets: (Type<any> | Function)[],
): TResult {
): TResult | undefined {
for (const target of targets) {
const result = this.get(metadataKeyOrDecorator, target);
if (result !== undefined) {

View File

@@ -43,7 +43,7 @@ export class ClientGrpcProxy
);
}
constructor(protected readonly options: GrpcOptions['options']) {
constructor(protected readonly options: Required<GrpcOptions>['options']) {
super();
this.url = this.getOptionsProp(options, 'url') || GRPC_DEFAULT_URL;
@@ -166,10 +166,10 @@ export class ClientGrpcProxy
methodName: string,
): (...args: any[]) => Observable<any> {
return (...args: any[]) => {
const isRequestStream = client[methodName].requestStream;
const isRequestStream = client![methodName].requestStream;
const stream = new Observable(observer => {
let isClientCanceled = false;
let upstreamSubscription: Subscription;
let upstreamSubscription: Subscription | null = null;
const upstreamSubjectOrData = args[0];
const maybeMetadata = args[1];
@@ -179,8 +179,8 @@ export class ClientGrpcProxy
const call =
isRequestStream && isUpstreamSubject
? client[methodName](maybeMetadata)
: client[methodName](...args);
? client![methodName](maybeMetadata)
: client![methodName](...args);
if (isRequestStream && isUpstreamSubject) {
upstreamSubscription = upstreamSubjectOrData.subscribe(
@@ -295,7 +295,7 @@ export class ClientGrpcProxy
public createClients(): any[] {
const grpcContext = this.loadProto();
const packageOption = this.getOptionsProp(this.options, 'package');
const grpcPackages = [];
const grpcPackages: any[] = [];
const packageNames = Array.isArray(packageOption)
? packageOption
: [packageOption];

View File

@@ -73,15 +73,15 @@ export class ClientKafka
}
get producer(): Producer {
if (!this._consumer) {
if (!this._producer) {
throw new Error(
'No producer initialized. Please, call the "connect" method first.',
);
}
return this._producer;
return this._producer!;
}
constructor(protected readonly options: KafkaOptions['options']) {
constructor(protected readonly options: Required<KafkaOptions>['options']) {
super();
const clientOptions = this.getOptionsProp(
@@ -135,7 +135,7 @@ export class ClientKafka
public async connect(): Promise<Producer> {
if (this.initialized) {
return this.initialized.then(() => this._producer);
return this.initialized.then(() => this._producer!);
}
/* eslint-disable-next-line no-async-promise-executor */
this.initialized = new Promise(async (resolve, reject) => {
@@ -160,7 +160,7 @@ export class ClientKafka
},
);
this._consumer = this.client.consumer(consumerOptions);
this._consumer = this.client!.consumer(consumerOptions);
this.registerConsumerEventListeners();
// Set member assignments on join and rebalance
@@ -172,7 +172,7 @@ export class ClientKafka
await this.bindTopics();
}
this._producer = this.client.producer(this.options.producer || {});
this._producer = this.client!.producer(this.options.producer || {});
this.registerProducerEventListeners();
await this._producer.connect();
@@ -181,7 +181,7 @@ export class ClientKafka
reject(err);
}
});
return this.initialized.then(() => this._producer);
return this.initialized.then(() => this._producer!);
}
public async bindTopics(): Promise<void> {
@@ -217,13 +217,13 @@ export class ClientKafka
public createResponseCallback(): (payload: EachMessagePayload) => any {
return async (payload: EachMessagePayload) => {
const rawMessage = this.parser.parse<KafkaMessage>(
const rawMessage = this.parser!.parse<KafkaMessage>(
Object.assign(payload.message, {
topic: payload.topic,
partition: payload.partition,
}),
);
if (isUndefined(rawMessage.headers[KafkaHeaders.CORRELATION_ID])) {
if (isUndefined(rawMessage.headers![KafkaHeaders.CORRELATION_ID])) {
return;
}
const { err, response, isDisposed, id } =
@@ -270,6 +270,9 @@ export class ClientKafka
}
protected registerConsumerEventListeners() {
if (!this._consumer) {
return;
}
this._consumer.on(this._consumer.events.CONNECT, () =>
this._status$.next(KafkaStatus.CONNECTED),
);
@@ -288,6 +291,9 @@ export class ClientKafka
}
protected registerProducerEventListeners() {
if (!this._producer) {
return;
}
this._producer.on(this._producer.events.CONNECT, () =>
this._status$.next(KafkaStatus.CONNECTED),
);
@@ -309,7 +315,7 @@ export class ClientKafka
this.options.send || {},
);
return this._producer.send(message);
return this._producer!.send(message);
}
protected getReplyTopicPartition(topic: string): string {
@@ -355,13 +361,14 @@ export class ClientKafka
this.options.send || {},
);
return this._producer.send(message);
return this._producer!.send(message);
})
.catch(err => errorCallback(err));
return cleanup;
} catch (err) {
errorCallback(err);
return () => null;
}
}

View File

@@ -28,8 +28,8 @@ export class ClientMqtt extends ClientProxy<MqttEvents, MqttStatus> {
protected readonly logger = new Logger(ClientProxy.name);
protected readonly subscriptionsCount = new Map<string, number>();
protected readonly url: string;
protected mqttClient: MqttClient;
protected connectionPromise: Promise<any>;
protected mqttClient: MqttClient | null = null;
protected connectionPromise: Promise<any> | null = null;
protected isInitialConnection = false;
protected isReconnecting = false;
protected pendingEventListeners: Array<{
@@ -37,7 +37,7 @@ export class ClientMqtt extends ClientProxy<MqttEvents, MqttStatus> {
callback: MqttEvents[keyof MqttEvents];
}> = [];
constructor(protected readonly options: MqttOptions['options']) {
constructor(protected readonly options: Required<MqttOptions>['options']) {
super();
this.url = this.getOptionsProp(this.options, 'url') ?? MQTT_DEFAULT_URL;
@@ -64,7 +64,7 @@ export class ClientMqtt extends ClientProxy<MqttEvents, MqttStatus> {
public connect(): Promise<any> {
if (this.mqttClient) {
return this.connectionPromise;
return this.connectionPromise!;
}
this.mqttClient = this.createClient();
this.registerErrorListener(this.mqttClient);
@@ -75,7 +75,7 @@ export class ClientMqtt extends ClientProxy<MqttEvents, MqttStatus> {
this.registerCloseListener(this.mqttClient);
this.pendingEventListeners.forEach(({ event, callback }) =>
this.mqttClient.on(event, callback),
this.mqttClient!.on(event, callback),
);
this.pendingEventListeners = [];
@@ -233,7 +233,7 @@ export class ClientMqtt extends ClientProxy<MqttEvents, MqttStatus> {
const options = serializedPacket.options;
delete serializedPacket.options;
this.mqttClient.publish(
this.mqttClient!.publish(
this.getRequestPattern(pattern),
JSON.stringify(serializedPacket),
this.mergePacketOptions(options),
@@ -241,7 +241,7 @@ export class ClientMqtt extends ClientProxy<MqttEvents, MqttStatus> {
};
if (subscriptionsCount <= 0) {
this.mqttClient.subscribe(
this.mqttClient!.subscribe(
responseChannel,
(err: any) => !err && publishPacket(),
);
@@ -255,6 +255,7 @@ export class ClientMqtt extends ClientProxy<MqttEvents, MqttStatus> {
};
} catch (err) {
callback({ err });
return () => {};
}
}
@@ -267,7 +268,7 @@ export class ClientMqtt extends ClientProxy<MqttEvents, MqttStatus> {
delete serializedPacket.options;
return new Promise<void>((resolve, reject) =>
this.mqttClient.publish(
this.mqttClient!.publish(
pattern,
JSON.stringify(serializedPacket),
this.mergePacketOptions(options),
@@ -277,11 +278,11 @@ export class ClientMqtt extends ClientProxy<MqttEvents, MqttStatus> {
}
protected unsubscribeFromChannel(channel: string) {
const subscriptionCount = this.subscriptionsCount.get(channel);
const subscriptionCount = this.subscriptionsCount.get(channel)!;
this.subscriptionsCount.set(channel, subscriptionCount - 1);
if (subscriptionCount - 1 <= 0) {
this.mqttClient.unsubscribe(channel);
this.mqttClient!.unsubscribe(channel);
}
}

View File

@@ -29,13 +29,13 @@ type NatsMsg = any;
export class ClientNats extends ClientProxy<NatsEvents, NatsStatus> {
protected readonly logger = new Logger(ClientNats.name);
protected natsClient: Client;
protected connectionPromise: Promise<Client>;
protected natsClient: Client | null = null;
protected connectionPromise: Promise<Client> | null = null;
protected statusEventEmitter = new EventEmitter<{
[key in keyof NatsEvents]: Parameters<NatsEvents[key]>;
}>();
constructor(protected readonly options: NatsOptions['options']) {
constructor(protected readonly options: Required<NatsOptions>['options']) {
super();
natsPackage = loadPackage('nats', ClientNats.name, () => require('nats'));
@@ -229,6 +229,7 @@ export class ClientNats extends ClientProxy<NatsEvents, NatsStatus> {
return () => subscription.unsubscribe();
} catch (err) {
callback({ err });
return () => {};
}
}

View File

@@ -49,21 +49,27 @@ export class ClientProxyFactory {
switch (transport) {
case Transport.REDIS:
return new ClientRedis(
options as RedisOptions['options'],
options as Required<RedisOptions>['options'],
) as ClientProxy;
case Transport.NATS:
return new ClientNats(options as NatsOptions['options']) as ClientProxy;
return new ClientNats(
options as Required<NatsOptions>['options'],
) as ClientProxy;
case Transport.MQTT:
return new ClientMqtt(options as MqttOptions['options']) as ClientProxy;
return new ClientMqtt(
options as Required<MqttOptions>['options'],
) as ClientProxy;
case Transport.GRPC:
return new ClientGrpcProxy(options as GrpcOptions['options']);
case Transport.RMQ:
return new ClientRMQ(options as RmqOptions['options']) as ClientProxy;
return new ClientRMQ(
options as Required<RmqOptions>['options'],
) as ClientProxy;
case Transport.KAFKA:
return new ClientKafka(options as KafkaOptions['options']);
return new ClientKafka(options as Required<KafkaOptions>['options']);
default:
return new ClientTCP(
options as TcpClientOptions['options'],
options as Required<TcpClientOptions>['options'],
) as ClientProxy;
}
}

View File

@@ -177,10 +177,28 @@ export abstract class ClientProxy<
}
protected getOptionsProp<
T extends ClientOptions['options'],
K extends keyof T,
>(obj: T, prop: K, defaultValue: T[K] = undefined) {
return obj && prop in obj ? obj[prop] : defaultValue;
Options extends ClientOptions['options'],
Attribute extends keyof Options,
>(obj: Options, prop: Attribute): Options[Attribute];
protected getOptionsProp<
Options extends ClientOptions['options'],
Attribute extends keyof Options,
DefaultValue extends Options[Attribute] = Options[Attribute],
>(
obj: Options,
prop: Attribute,
defaultValue: DefaultValue,
): Required<Options>[Attribute];
protected getOptionsProp<
Options extends ClientOptions['options'],
Attribute extends keyof Options,
DefaultValue extends Options[Attribute] = Options[Attribute],
>(
obj: Options,
prop: Attribute,
defaultValue: DefaultValue = undefined as DefaultValue,
) {
return obj && prop in obj ? obj![prop] : defaultValue;
}
protected normalizePattern(pattern: MsPattern): string {
@@ -190,30 +208,26 @@ export abstract class ClientProxy<
protected initializeSerializer(options: ClientOptions['options']) {
this.serializer =
(options &&
(
options as
| RedisOptions['options']
| NatsOptions['options']
| MqttOptions['options']
| TcpClientOptions['options']
| RmqOptions['options']
| KafkaOptions['options']
).serializer) ||
(options as
| RedisOptions['options']
| NatsOptions['options']
| MqttOptions['options']
| TcpClientOptions['options']
| RmqOptions['options']
| KafkaOptions['options'])!.serializer) ||
new IdentitySerializer();
}
protected initializeDeserializer(options: ClientOptions['options']) {
this.deserializer =
(options &&
(
options as
| RedisOptions['options']
| NatsOptions['options']
| MqttOptions['options']
| TcpClientOptions['options']
| RmqOptions['options']
| KafkaOptions['options']
).deserializer) ||
(options as
| RedisOptions['options']
| NatsOptions['options']
| MqttOptions['options']
| TcpClientOptions['options']
| RmqOptions['options']
| KafkaOptions['options'])!.deserializer) ||
new IncomingResponseDeserializer();
}
}

View File

@@ -34,7 +34,7 @@ export class ClientRedis extends ClientProxy<RedisEvents, RedisStatus> {
callback: RedisEvents[keyof RedisEvents];
}> = [];
constructor(protected readonly options: RedisOptions['options']) {
constructor(protected readonly options: Required<RedisOptions>['options']) {
super();
redisPackage = loadPackage('ioredis', ClientRedis.name, () =>
@@ -209,11 +209,11 @@ export class ClientRedis extends ClientProxy<RedisEvents, RedisStatus> {
);
return;
}
if (times > this.getOptionsProp(this.options, 'retryAttempts')) {
if (times > this.getOptionsProp(this.options, 'retryAttempts', 0)) {
this.logger.error('Retry time exhausted');
return;
}
return this.getOptionsProp(this.options, 'retryDelay') ?? 5000;
return this.getOptionsProp(this.options, 'retryDelay', 5000);
}
public createResponseCallback(): (
@@ -280,6 +280,7 @@ export class ClientRedis extends ClientProxy<RedisEvents, RedisStatus> {
};
} catch (err) {
callback({ err });
return () => {};
}
}
@@ -295,7 +296,7 @@ export class ClientRedis extends ClientProxy<RedisEvents, RedisStatus> {
}
protected unsubscribeFromChannel(channel: string) {
const subscriptionCount = this.subscriptionsCount.get(channel);
const subscriptionCount = this.subscriptionsCount.get(channel)!;
this.subscriptionsCount.set(channel, subscriptionCount - 1);
if (subscriptionCount - 1 <= 0) {

View File

@@ -68,15 +68,19 @@ export class ClientRMQ extends ClientProxy<RmqEvents, RmqStatus> {
protected replyQueue: string;
protected noAssert: boolean;
constructor(protected readonly options: RmqOptions['options']) {
constructor(protected readonly options: Required<RmqOptions>['options']) {
super();
this.queue =
this.getOptionsProp(this.options, 'queue') || RQM_DEFAULT_QUEUE;
this.queueOptions =
this.getOptionsProp(this.options, 'queueOptions') ||
RQM_DEFAULT_QUEUE_OPTIONS;
this.replyQueue =
this.getOptionsProp(this.options, 'replyQueue') || REPLY_QUEUE;
this.queue = this.getOptionsProp(this.options, 'queue', RQM_DEFAULT_QUEUE);
this.queueOptions = this.getOptionsProp(
this.options,
'queueOptions',
RQM_DEFAULT_QUEUE_OPTIONS,
);
this.replyQueue = this.getOptionsProp(
this.options,
'replyQueue',
REPLY_QUEUE,
);
this.noAssert =
this.getOptionsProp(this.options, 'noAssert') ??
this.queueOptions.noAssert ??
@@ -300,7 +304,10 @@ export class ClientRMQ extends ClientProxy<RmqEvents, RmqStatus> {
): Promise<void>;
public async handleMessage(
packet: unknown,
options: Record<string, unknown> | ((packet: WritePacket) => any),
options:
| Record<string, unknown>
| ((packet: WritePacket) => any)
| undefined,
callback?: (packet: WritePacket) => any,
): Promise<void> {
if (isFunction(options)) {
@@ -313,13 +320,13 @@ export class ClientRMQ extends ClientProxy<RmqEvents, RmqStatus> {
options,
);
if (isDisposed || err) {
callback({
callback?.({
err,
response,
isDisposed: true,
});
}
callback({
callback?.({
err,
response,
});
@@ -372,6 +379,7 @@ export class ClientRMQ extends ClientProxy<RmqEvents, RmqStatus> {
return () => this.responseEmitter.removeListener(correlationId, listener);
} catch (err) {
callback({ err });
return () => {};
}
}

View File

@@ -19,19 +19,18 @@ export class ClientTCP extends ClientProxy<TcpEvents, TcpStatus> {
protected readonly host: string;
protected readonly socketClass: Type<TcpSocket>;
protected readonly tlsOptions?: ConnectionOptions;
protected socket: TcpSocket;
protected connectionPromise: Promise<any>;
protected socket: TcpSocket | null = null;
protected connectionPromise: Promise<any> | null = null;
protected pendingEventListeners: Array<{
event: keyof TcpEvents;
callback: TcpEvents[keyof TcpEvents];
}> = [];
constructor(options: TcpClientOptions['options']) {
constructor(options: Required<TcpClientOptions>['options']) {
super();
this.port = this.getOptionsProp(options, 'port') || TCP_DEFAULT_PORT;
this.host = this.getOptionsProp(options, 'host') || TCP_DEFAULT_HOST;
this.socketClass =
this.getOptionsProp(options, 'socketClass') || JsonSocket;
this.port = this.getOptionsProp(options, 'port', TCP_DEFAULT_PORT);
this.host = this.getOptionsProp(options, 'host', TCP_DEFAULT_HOST);
this.socketClass = this.getOptionsProp(options, 'socketClass', JsonSocket);
this.tlsOptions = this.getOptionsProp(options, 'tlsOptions');
this.initializeSerializer(options);
@@ -48,13 +47,13 @@ export class ClientTCP extends ClientProxy<TcpEvents, TcpStatus> {
this.registerErrorListener(this.socket);
this.pendingEventListeners.forEach(({ event, callback }) =>
this.socket.on(event, callback as any),
this.socket!.on(event, callback as any),
);
this.pendingEventListeners = [];
const source$ = this.connect$(this.socket.netSocket).pipe(
tap(() => {
this.socket.on('message', (buffer: WritePacket & PacketId) =>
this.socket!.on('message', (buffer: WritePacket & PacketId) =>
this.handleResponse(buffer),
);
}),
@@ -105,7 +104,6 @@ export class ClientTCP extends ClientProxy<TcpEvents, TcpStatus> {
...this.tlsOptions,
port: this.port,
host: this.host,
socket,
});
} else {
socket = new net.Socket();
@@ -148,7 +146,7 @@ export class ClientTCP extends ClientProxy<TcpEvents, TcpStatus> {
public handleClose() {
this.socket = null;
this.connectionPromise = undefined;
this.connectionPromise = null;
if (this.routingMap.size > 0) {
const err = new Error('Connection closed');
@@ -188,11 +186,12 @@ export class ClientTCP extends ClientProxy<TcpEvents, TcpStatus> {
const serializedPacket = this.serializer.serialize(packet);
this.routingMap.set(packet.id, callback);
this.socket.sendMessage(serializedPacket);
this.socket!.sendMessage(serializedPacket);
return () => this.routingMap.delete(packet.id);
} catch (err) {
callback({ err });
return () => {};
}
}
@@ -202,6 +201,6 @@ export class ClientTCP extends ClientProxy<TcpEvents, TcpStatus> {
...packet,
pattern,
});
return this.socket.sendMessage(serializedPacket);
return this.socket!.sendMessage(serializedPacket);
}
}

View File

@@ -1,17 +1,17 @@
import {
isObject,
isNumber,
isNil,
isNumber,
isObject,
isSymbol,
} from '@nestjs/common/utils/shared.utils';
import {
PATTERN_EXTRAS_METADATA,
PATTERN_HANDLER_METADATA,
PATTERN_METADATA,
TRANSPORT_METADATA,
PATTERN_EXTRAS_METADATA,
} from '../constants';
import { PatternHandler } from '../enums/pattern-handler.enum';
import { Transport } from '../enums';
import { PatternHandler } from '../enums/pattern-handler.enum';
/**
* Subscribes to incoming events which fulfils chosen pattern.
@@ -43,7 +43,7 @@ export const EventPattern: {
extras = transportOrExtras;
} else {
transport = transportOrExtras as Transport | symbol;
extras = maybeExtras;
extras = maybeExtras!;
}
return (
target: object,
@@ -52,7 +52,7 @@ export const EventPattern: {
) => {
Reflect.defineMetadata(
PATTERN_METADATA,
[].concat(metadata),
([] as any[]).concat(metadata),
descriptor.value,
);
Reflect.defineMetadata(

View File

@@ -1,23 +1,23 @@
import {
isObject,
isNumber,
isNil,
isNumber,
isObject,
isSymbol,
} from '@nestjs/common/utils/shared.utils';
import {
PATTERN_EXTRAS_METADATA,
PATTERN_HANDLER_METADATA,
PATTERN_METADATA,
TRANSPORT_METADATA,
PATTERN_EXTRAS_METADATA,
} from '../constants';
import { PatternHandler } from '../enums/pattern-handler.enum';
import { PatternMetadata } from '../interfaces/pattern-metadata.interface';
import { Transport } from '../enums';
import { PatternHandler } from '../enums/pattern-handler.enum';
import {
InvalidGrpcDecoratorException,
RpcDecoratorMetadata,
} from '../errors/invalid-grpc-message-decorator.exception';
import { PatternMetadata } from '../interfaces/pattern-metadata.interface';
export enum GrpcMethodStreamingType {
NO_STREAMING = 'no_stream',
@@ -61,8 +61,9 @@ export const MessagePattern: {
extras = transportOrExtras;
} else {
transport = transportOrExtras as Transport | symbol;
extras = maybeExtras;
extras = maybeExtras!;
}
return (
target: object,
key: string | symbol,
@@ -71,7 +72,7 @@ export const MessagePattern: {
try {
Reflect.defineMetadata(
PATTERN_METADATA,
[].concat(metadata),
([] as any[]).concat(metadata),
descriptor.value,
);
Reflect.defineMetadata(
@@ -100,7 +101,10 @@ export const MessagePattern: {
*/
export function GrpcMethod(service?: string): MethodDecorator;
export function GrpcMethod(service: string, method?: string): MethodDecorator;
export function GrpcMethod(service: string, method?: string): MethodDecorator {
export function GrpcMethod(
service: string | undefined,
method?: string,
): MethodDecorator {
return (
target: object,
key: string | symbol,
@@ -126,7 +130,7 @@ export function GrpcStreamMethod(
method?: string,
): MethodDecorator;
export function GrpcStreamMethod(
service: string,
service: string | undefined,
method?: string,
): MethodDecorator {
return (
@@ -160,7 +164,7 @@ export function GrpcStreamCall(
method?: string,
): MethodDecorator;
export function GrpcStreamCall(
service: string,
service: string | undefined,
method?: string,
): MethodDecorator {
return (

View File

@@ -18,9 +18,8 @@ export class RpcException extends Error {
) {
this.message = (this.error as Record<string, any>).message;
} else if (this.constructor) {
this.message = this.constructor.name
.match(/[A-Z][a-z]+|[0-9]+/g)
.join(' ');
this.message =
this.constructor!.name!.match(/[A-Z][a-z]+|[0-9]+/g)!.join(' ');
}
}

View File

@@ -39,8 +39,9 @@ export class ListenerMetadataExplorer {
const instancePrototype = Object.getPrototypeOf(instance);
return this.metadataScanner
.getAllMethodNames(instancePrototype)
.map(method =>
this.exploreMethodMetadata(instance, instancePrototype, method),
.map(
method =>
this.exploreMethodMetadata(instance, instancePrototype, method)!,
)
.filter(metadata => metadata);
}
@@ -49,7 +50,7 @@ export class ListenerMetadataExplorer {
instance: Controller,
instancePrototype: object,
methodKey: string,
): EventOrMessageListenerDefinition {
): EventOrMessageListenerDefinition | undefined {
const prototypeCallback = instancePrototype[methodKey];
const handlerType = Reflect.getMetadata(
PATTERN_HANDLER_METADATA,

View File

@@ -85,7 +85,7 @@ export class ListenersController {
acc.push({ ...handler, patterns: [pattern] }),
);
return acc;
}, [])
}, [] as EventOrMessageListenerDefinition[])
.forEach((definition: EventOrMessageListenerDefinition) => {
const {
patterns: [pattern],
@@ -98,7 +98,7 @@ export class ListenersController {
this.insertEntrypointDefinition(
instanceWrapper,
definition,
serverInstance.transportId,
serverInstance.transportId!,
);
if (isStatic) {

View File

@@ -1,8 +1,10 @@
import {
DynamicModule,
ForwardReference,
Module,
OnApplicationShutdown,
Provider,
Type,
} from '@nestjs/common';
import { ClientProxy, ClientProxyFactory } from '../client';
import {
@@ -44,7 +46,9 @@ export class ClientsModule {
option.imports && !accImports.includes(option.imports)
? accImports.concat(option.imports)
: accImports,
[],
[] as Array<
DynamicModule | Promise<DynamicModule> | ForwardReference | Type
>,
);
return {
module: ClientsModule,
@@ -64,8 +68,8 @@ export class ClientsModule {
return [
this.createAsyncOptionsProvider(options),
{
provide: options.useClass,
useClass: options.useClass,
provide: options.useClass!,
useClass: options.useClass!,
},
];
}
@@ -86,7 +90,7 @@ export class ClientsModule {
(optionsFactory: ClientsModuleOptionsFactory) =>
optionsFactory.createClientOptions(),
),
inject: [options.useExisting || options.useClass],
inject: [options.useExisting || options.useClass!],
};
}
@@ -94,7 +98,7 @@ export class ClientsModule {
useFactory: ClientsProviderAsyncOptions['useFactory'],
) {
return async (...args: any[]) => {
const clientOptions = await useFactory(...args);
const clientOptions = await useFactory!(...args);
const clientProxyRef = ClientProxyFactory.create(clientOptions);
return this.assignOnAppShutdownHook(clientProxyRef);
};

View File

@@ -64,7 +64,7 @@ export class NestMicroservice
) {
super(container, config);
this.injector = new Injector({ preview: config.preview });
this.injector = new Injector({ preview: config.preview! });
this.microservicesModule.register(
container,
this.graphInspector,

View File

@@ -1,8 +1,14 @@
import { Transport } from '../enums/transport.enum';
import {
CustomStrategy,
GrpcOptions,
KafkaOptions,
MicroserviceOptions,
MqttOptions,
NatsOptions,
RedisOptions,
RmqOptions,
TcpOptions,
} from '../interfaces';
import { ServerGrpc } from './server-grpc';
import { ServerKafka } from './server-kafka';
@@ -20,19 +26,19 @@ export class ServerFactory {
>;
switch (transport) {
case Transport.REDIS:
return new ServerRedis(options);
return new ServerRedis(options as Required<RedisOptions>['options']);
case Transport.NATS:
return new ServerNats(options);
return new ServerNats(options as Required<NatsOptions>['options']);
case Transport.MQTT:
return new ServerMqtt(options);
return new ServerMqtt(options as Required<MqttOptions>['options']);
case Transport.GRPC:
return new ServerGrpc(options);
return new ServerGrpc(options as Required<GrpcOptions>['options']);
case Transport.KAFKA:
return new ServerKafka(options);
return new ServerKafka(options as Required<KafkaOptions>['options']);
case Transport.RMQ:
return new ServerRMQ(options);
return new ServerRMQ(options as Required<RmqOptions>['options']);
default:
return new ServerTCP(options);
return new ServerTCP(options as Required<TcpOptions>['options']);
}
}
}

View File

@@ -63,7 +63,7 @@ export class ServerGrpc extends Server<never, never> {
);
}
constructor(private readonly options: GrpcOptions['options']) {
constructor(private readonly options: Readonly<GrpcOptions>['options']) {
super();
this.url = this.getOptionsProp(options, 'url') || GRPC_DEFAULT_URL;
@@ -96,7 +96,7 @@ export class ServerGrpc extends Server<never, never> {
public async start(callback?: () => void) {
await this.bindEvents();
callback();
callback?.();
}
public async bindEvents() {
@@ -136,7 +136,7 @@ export class ServerGrpc extends Server<never, never> {
const service = {};
for (const methodName in grpcService.prototype) {
let methodHandler = null;
let methodHandler: MessageHandler | null = null;
let streamingType = GrpcMethodStreamingType.NO_STREAMING;
const methodFunction = grpcService.prototype[methodName];
@@ -190,13 +190,13 @@ export class ServerGrpc extends Server<never, never> {
methodName: string,
streaming: GrpcMethodStreamingType,
grpcMethod: { path?: string },
) {
): MessageHandler {
let pattern = this.createPattern(serviceName, methodName, streaming);
let methodHandler = this.messageHandlers.get(pattern);
let methodHandler = this.messageHandlers.get(pattern)!;
if (!methodHandler) {
const packageServiceName = grpcMethod.path?.split?.('/')[1];
pattern = this.createPattern(packageServiceName, methodName, streaming);
methodHandler = this.messageHandlers.get(pattern);
pattern = this.createPattern(packageServiceName!, methodName, streaming);
methodHandler = this.messageHandlers.get(pattern)!;
}
return methodHandler;
}

View File

@@ -39,23 +39,28 @@ export class ServerKafka extends Server<never, KafkaStatus> {
public readonly transportId = Transport.KAFKA;
protected logger = new Logger(ServerKafka.name);
protected client: Kafka = null;
protected consumer: Consumer = null;
protected producer: Producer = null;
protected parser: KafkaParser = null;
protected client: Kafka | null = null;
protected consumer: Consumer | null = null;
protected producer: Producer | null = null;
protected parser: KafkaParser | null = null;
protected brokers: string[] | BrokersFunction;
protected clientId: string;
protected groupId: string;
constructor(protected readonly options: KafkaOptions['options']) {
constructor(protected readonly options: Required<KafkaOptions>['options']) {
super();
const clientOptions =
this.getOptionsProp(this.options, 'client') || ({} as KafkaConfig);
const consumerOptions =
this.getOptionsProp(this.options, 'consumer') || ({} as ConsumerConfig);
const postfixId =
this.getOptionsProp(this.options, 'postfixId') ?? '-server';
const clientOptions = this.getOptionsProp(
this.options,
'client',
{} as KafkaConfig,
);
const consumerOptions = this.getOptionsProp(
this.options,
'consumer',
{} as ConsumerConfig,
);
const postfixId = this.getOptionsProp(this.options, 'postfixId', '-server');
this.brokers = clientOptions.brokers || [KAFKA_DEFAULT_BROKER];
@@ -98,8 +103,8 @@ export class ServerKafka extends Server<never, KafkaStatus> {
const consumerOptions = Object.assign(this.options.consumer || {}, {
groupId: this.groupId,
});
this.consumer = this.client.consumer(consumerOptions);
this.producer = this.client.producer(this.options.producer);
this.consumer = this.client!.consumer(consumerOptions);
this.producer = this.client!.producer(this.options.producer);
this.registerConsumerEventListeners();
this.registerProducerEventListeners();
@@ -110,6 +115,9 @@ export class ServerKafka extends Server<never, KafkaStatus> {
}
protected registerConsumerEventListeners() {
if (!this.consumer) {
return;
}
this.consumer.on(this.consumer.events.CONNECT, () =>
this._status$.next(KafkaStatus.CONNECTED),
);
@@ -128,6 +136,9 @@ export class ServerKafka extends Server<never, KafkaStatus> {
}
protected registerProducerEventListeners() {
if (!this.producer) {
return;
}
this.producer.on(this.producer.events.CONNECT, () =>
this._status$.next(KafkaStatus.CONNECTED),
);
@@ -151,7 +162,7 @@ export class ServerKafka extends Server<never, KafkaStatus> {
const consumerSubscribeOptions = this.options.subscribe || {};
if (registeredPatterns.length > 0) {
await this.consumer.subscribe({
await this.consumer!.subscribe({
...consumerSubscribeOptions,
topics: registeredPatterns,
});
@@ -178,7 +189,7 @@ export class ServerKafka extends Server<never, KafkaStatus> {
public async handleMessage(payload: EachMessagePayload) {
const channel = payload.topic;
const rawMessage = this.parser.parse<KafkaMessage>(
const rawMessage = this.parser!.parse<KafkaMessage>(
Object.assign(payload.message, {
topic: payload.topic,
partition: payload.partition,
@@ -194,9 +205,9 @@ export class ServerKafka extends Server<never, KafkaStatus> {
rawMessage,
payload.partition,
payload.topic,
this.consumer,
this.consumer!,
payload.heartbeat,
this.producer,
this.producer!,
]);
const handler = this.getHandlerByPattern(packet.pattern);
// if the correlation id or reply topic is not set
@@ -291,7 +302,7 @@ export class ServerKafka extends Server<never, KafkaStatus> {
},
this.options.send || {},
);
return this.producer.send(replyMessage);
return this.producer!.send(replyMessage);
}
public assignIsDisposedHeader(
@@ -301,7 +312,7 @@ export class ServerKafka extends Server<never, KafkaStatus> {
if (!outgoingResponse.isDisposed) {
return;
}
outgoingMessage.headers[KafkaHeaders.NEST_IS_DISPOSED] = Buffer.alloc(1);
outgoingMessage.headers![KafkaHeaders.NEST_IS_DISPOSED] = Buffer.alloc(1);
}
public assignErrorHeader(
@@ -315,7 +326,7 @@ export class ServerKafka extends Server<never, KafkaStatus> {
typeof outgoingResponse.err === 'object'
? JSON.stringify(outgoingResponse.err)
: outgoingResponse.err;
outgoingMessage.headers[KafkaHeaders.NEST_ERR] =
outgoingMessage.headers![KafkaHeaders.NEST_ERR] =
Buffer.from(stringifiedError);
}
@@ -323,7 +334,7 @@ export class ServerKafka extends Server<never, KafkaStatus> {
correlationId: string,
outgoingMessage: Message,
) {
outgoingMessage.headers[KafkaHeaders.CORRELATION_ID] =
outgoingMessage.headers![KafkaHeaders.CORRELATION_ID] =
Buffer.from(correlationId);
}

View File

@@ -41,9 +41,9 @@ export class ServerMqtt extends Server<MqttEvents, MqttStatus> {
callback: MqttEvents[keyof MqttEvents];
}> = [];
constructor(private readonly options: MqttOptions['options']) {
constructor(private readonly options: Required<MqttOptions>['options']) {
super();
this.url = this.getOptionsProp(options, 'url') || MQTT_DEFAULT_URL;
this.url = this.getOptionsProp(options, 'url', MQTT_DEFAULT_URL);
mqttPackage = this.loadPackage('mqtt', ServerMqtt.name, () =>
require('mqtt'),
@@ -87,7 +87,7 @@ export class ServerMqtt extends Server<MqttEvents, MqttStatus> {
const registeredPatterns = [...this.messageHandlers.keys()];
registeredPatterns.forEach(pattern => {
const { isEventHandler } = this.messageHandlers.get(pattern);
const { isEventHandler } = this.messageHandlers.get(pattern)!;
mqttClient.subscribe(
isEventHandler ? pattern : this.getRequestPattern(pattern),
this.getOptionsProp(this.options, 'subscribeOptions'),
@@ -120,7 +120,7 @@ export class ServerMqtt extends Server<MqttEvents, MqttStatus> {
): Promise<any> {
const rawPacket = this.parseMessage(buffer.toString());
const packet = await this.deserializer.deserialize(rawPacket, { channel });
const mqttContext = new MqttContext([channel, originalPacket]);
const mqttContext = new MqttContext([channel, originalPacket!]);
if (isUndefined((packet as IncomingRequest).id)) {
return this.handleEvent(channel, packet, mqttContext);
}

View File

@@ -44,7 +44,7 @@ export class ServerNats<
}>();
private readonly subscriptions: Subscription[] = [];
constructor(private readonly options: NatsOptions['options']) {
constructor(private readonly options: Required<NatsOptions>['options']) {
super();
natsPackage = this.loadPackage('nats', ServerNats.name, () =>
@@ -211,7 +211,7 @@ export class ServerNats<
case 'pingTimer':
if (this.options.debug) {
this.logger.debug(
this.logger.debug!(
`NatsStatus: type: "${status.type}", data: "${data}".`,
);
}

View File

@@ -38,7 +38,7 @@ export class ServerRedis extends Server<RedisEvents, RedisStatus> {
callback: RedisEvents[keyof RedisEvents];
}> = [];
constructor(protected readonly options: RedisOptions['options']) {
constructor(protected readonly options: Required<RedisOptions>['options']) {
super();
redisPackage = this.loadPackage('ioredis', ServerRedis.name, () =>
@@ -78,7 +78,7 @@ export class ServerRedis extends Server<RedisEvents, RedisStatus> {
Promise.all([this.subClient.connect(), this.pubClient.connect()])
.then(() => {
this.bindEvents(this.subClient, this.pubClient);
callback();
callback?.();
})
.catch(callback);
}
@@ -90,7 +90,7 @@ export class ServerRedis extends Server<RedisEvents, RedisStatus> {
);
const subscribePatterns = [...this.messageHandlers.keys()];
subscribePatterns.forEach(pattern => {
const { isEventHandler } = this.messageHandlers.get(pattern);
const { isEventHandler } = this.messageHandlers.get(pattern)!;
const channel = isEventHandler
? pattern
@@ -258,11 +258,11 @@ export class ServerRedis extends Server<RedisEvents, RedisStatus> {
);
return;
}
if (times > this.getOptionsProp(this.options, 'retryAttempts')) {
if (times > this.getOptionsProp(this.options, 'retryAttempts', 0)) {
this.logger.error(`Retry time exhausted`);
return;
}
return this.getOptionsProp(this.options, 'retryDelay') ?? 5000;
return this.getOptionsProp(this.options, 'retryDelay', 5000);
}
public unwrap<T>(): T {

View File

@@ -65,7 +65,7 @@ export class ServerRMQ extends Server<RmqEvents, RmqStatus> {
callback: RmqEvents[keyof RmqEvents];
}> = [];
constructor(protected readonly options: RmqOptions['options']) {
constructor(protected readonly options: Required<RmqOptions>['options']) {
super();
this.urls = this.getOptionsProp(this.options, 'urls') || [RQM_DEFAULT_URL];
this.queue =
@@ -113,7 +113,7 @@ export class ServerRMQ extends Server<RmqEvents, RmqStatus> {
this._status$.next(RmqStatus.CONNECTED);
this.channel = this.server.createChannel({
json: false,
setup: (channel: any) => this.setupChannel(channel, callback),
setup: (channel: any) => this.setupChannel(channel, callback!),
});
});

View File

@@ -41,7 +41,7 @@ export class ServerTCP extends Server<TcpEvents, TcpStatus> {
callback: TcpEvents[keyof TcpEvents];
}> = [];
constructor(private readonly options: TcpOptions['options']) {
constructor(private readonly options: Required<TcpOptions>['options']) {
super();
this.port = this.getOptionsProp(options, 'port', TCP_DEFAULT_PORT);
this.host = this.getOptionsProp(options, 'host', TCP_DEFAULT_HOST);
@@ -121,14 +121,14 @@ export class ServerTCP extends Server<TcpEvents, TcpStatus> {
this.isManuallyTerminated ||
!this.getOptionsProp(this.options, 'retryAttempts') ||
this.retryAttemptsCount >=
this.getOptionsProp(this.options, 'retryAttempts')
this.getOptionsProp(this.options, 'retryAttempts', 0)
) {
return undefined;
}
++this.retryAttemptsCount;
return setTimeout(
() => this.server.listen(this.port, this.host),
this.getOptionsProp(this.options, 'retryDelay') || 0,
this.getOptionsProp(this.options, 'retryDelay', 0),
);
}

View File

@@ -102,7 +102,7 @@ export abstract class Server<
callback.extras = extras;
if (this.messageHandlers.has(normalizedPattern) && isEventHandler) {
const headRef = this.messageHandlers.get(normalizedPattern);
const headRef = this.messageHandlers.get(normalizedPattern)!;
const getTail = (handler: MessageHandler) =>
handler?.next ? getTail(handler.next) : handler;
@@ -120,7 +120,7 @@ export abstract class Server<
public getHandlerByPattern(pattern: string): MessageHandler | null {
const route = this.getRouteFromPattern(pattern);
return this.messageHandlers.has(route)
? this.messageHandlers.get(route)
? this.messageHandlers.get(route)!
: null;
}
@@ -128,12 +128,13 @@ export abstract class Server<
stream$: Observable<any>,
respond: (data: WritePacket) => Promise<unknown> | void,
): Subscription {
let dataBuffer: WritePacket[] = null;
let dataBuffer: WritePacket[] | null = null;
const scheduleOnNextTick = (data: WritePacket) => {
if (!dataBuffer) {
dataBuffer = [data];
process.nextTick(async () => {
for (const item of dataBuffer) {
for (const item of dataBuffer!) {
await respond(item);
}
dataBuffer = null;
@@ -197,10 +198,28 @@ export abstract class Server<
}
public getOptionsProp<
T extends MicroserviceOptions['options'],
K extends keyof T,
>(obj: T, prop: K, defaultValue: T[K] = undefined) {
return obj && prop in obj ? obj[prop] : defaultValue;
Options extends MicroserviceOptions['options'],
Attribute extends keyof Options,
>(obj: Options, prop: Attribute): Options[Attribute];
public getOptionsProp<
Options extends MicroserviceOptions['options'],
Attribute extends keyof Options,
DefaultValue extends Options[Attribute] = Options[Attribute],
>(
obj: Options,
prop: Attribute,
defaultValue: DefaultValue,
): Required<Options>[Attribute];
public getOptionsProp<
Options extends MicroserviceOptions['options'],
Attribute extends keyof Options,
DefaultValue extends Options[Attribute] = Options[Attribute],
>(
obj: Options,
prop: Attribute,
defaultValue: DefaultValue = undefined as DefaultValue,
) {
return obj && prop in obj ? obj![prop] : defaultValue;
}
protected handleError(error: string) {
@@ -218,30 +237,26 @@ export abstract class Server<
protected initializeSerializer(options: ClientOptions['options']) {
this.serializer =
(options &&
(
options as
| RedisOptions['options']
| NatsOptions['options']
| MqttOptions['options']
| TcpOptions['options']
| RmqOptions['options']
| KafkaOptions['options']
).serializer) ||
(options as
| RedisOptions['options']
| NatsOptions['options']
| MqttOptions['options']
| TcpOptions['options']
| RmqOptions['options']
| KafkaOptions['options'])!.serializer) ||
new IdentitySerializer();
}
protected initializeDeserializer(options: ClientOptions['options']) {
this.deserializer =
(options &&
(
options as
| RedisOptions['options']
| NatsOptions['options']
| MqttOptions['options']
| TcpOptions['options']
| RmqOptions['options']
| KafkaOptions['options']
).deserializer) ||
(options! &&
(options as
| RedisOptions['options']
| NatsOptions['options']
| MqttOptions['options']
| TcpOptions['options']
| RmqOptions['options']
| KafkaOptions['options'])!.deserializer) ||
new IncomingRequestDeserializer();
}

View File

@@ -11,12 +11,13 @@ export function createRpcParamDecorator(
return (...pipes: (Type<PipeTransform> | PipeTransform)[]) =>
(target, key, index) => {
const args =
Reflect.getMetadata(PARAM_ARGS_METADATA, target.constructor, key) || {};
Reflect.getMetadata(PARAM_ARGS_METADATA, target.constructor, key!) ||
{};
Reflect.defineMetadata(
PARAM_ARGS_METADATA,
assignMetadata(args, paramtype, index, undefined, ...pipes),
target.constructor,
key,
key!,
);
};
}
@@ -29,7 +30,7 @@ export const createPipesRpcParamDecorator =
): ParameterDecorator =>
(target, key, index) => {
const args =
Reflect.getMetadata(PARAM_ARGS_METADATA, target.constructor, key) || {};
Reflect.getMetadata(PARAM_ARGS_METADATA, target.constructor, key!) || {};
const hasParamData = isNil(data) || isString(data);
const paramData = hasParamData ? data : undefined;
@@ -37,8 +38,8 @@ export const createPipesRpcParamDecorator =
Reflect.defineMetadata(
PARAM_ARGS_METADATA,
assignMetadata(args, paramtype, index, paramData, ...paramPipes),
assignMetadata(args, paramtype, index, paramData!, ...paramPipes),
target.constructor,
key,
key!,
);
};

View File

@@ -1,13 +1,12 @@
import type { Server } from 'http';
import {
HttpStatus,
InternalServerErrorException,
Logger,
RequestMethod,
StreamableFile,
VERSION_NEUTRAL,
VersioningOptions,
VersioningType,
VERSION_NEUTRAL,
} from '@nestjs/common';
import { VersionValue } from '@nestjs/common/interfaces';
import {
@@ -24,13 +23,14 @@ import {
} from '@nestjs/common/utils/shared.utils';
import { AbstractHttpAdapter } from '@nestjs/core/adapters/http-adapter';
import { RouterMethodFactory } from '@nestjs/core/helpers/router-method-factory';
import * as bodyparser from 'body-parser';
import {
json as bodyParserJson,
urlencoded as bodyParserUrlencoded,
} from 'body-parser';
import * as bodyparser from 'body-parser';
import * as cors from 'cors';
import * as express from 'express';
import type { Server } from 'http';
import * as http from 'http';
import * as https from 'https';
import { Duplex, pipeline } from 'stream';
@@ -94,7 +94,7 @@ export class ExpressAdapter extends AbstractHttpAdapter<
body.errorHandler(err, response);
}),
response,
(err: Error) => {
(err: any) => {
if (err) {
body.errorLogger(err);
}
@@ -218,7 +218,7 @@ export class ExpressAdapter extends AbstractHttpAdapter<
}
public enableCors(options: CorsOptions | CorsOptionsDelegate<any>) {
return this.use(cors(options));
return this.use(cors(options as any));
}
public createMiddlewareFactory(
@@ -233,7 +233,7 @@ export class ExpressAdapter extends AbstractHttpAdapter<
const isHttpsEnabled = options && options.httpsOptions;
if (isHttpsEnabled) {
this.httpServer = https.createServer(
options.httpsOptions,
options.httpsOptions!,
this.getInstance(),
);
} else {
@@ -246,8 +246,8 @@ export class ExpressAdapter extends AbstractHttpAdapter<
}
public registerParserMiddleware(prefix?: string, rawBody?: boolean) {
const bodyParserJsonOptions = getBodyParserOptions(rawBody);
const bodyParserUrlencodedOptions = getBodyParserOptions(rawBody, {
const bodyParserJsonOptions = getBodyParserOptions(rawBody!);
const bodyParserUrlencodedOptions = getBodyParserOptions(rawBody!, {
extended: true,
});
@@ -260,13 +260,15 @@ export class ExpressAdapter extends AbstractHttpAdapter<
.forEach(parserKey => this.use(parserMiddleware[parserKey]));
}
public useBodyParser<Options = NestExpressBodyParserOptions>(
public useBodyParser<
Options extends NestExpressBodyParserOptions = NestExpressBodyParserOptions,
>(
type: NestExpressBodyParserType,
rawBody: boolean,
options?: Omit<Options, 'verify'>,
): this {
const parserOptions = getBodyParserOptions<Options>(rawBody, options);
const parser = bodyparser[type](parserOptions);
const parser = bodyparser[type](parserOptions!);
this.use(parser);
@@ -425,6 +427,8 @@ export class ExpressAdapter extends AbstractHttpAdapter<
return handlerForHeaderVersioning;
}
throw new Error('Unsupported versioning options');
}
private trackOpenConnections() {

View File

@@ -51,8 +51,8 @@ export class MulterModule {
return [
this.createAsyncOptionsProvider(options),
{
provide: options.useClass,
useClass: options.useClass,
provide: options.useClass!,
useClass: options.useClass!,
},
];
}
@@ -71,7 +71,7 @@ export class MulterModule {
provide: MULTER_MODULE_OPTIONS,
useFactory: async (optionsFactory: MulterOptionsFactory) =>
optionsFactory.createMulterOptions(),
inject: [options.useExisting || options.useClass],
inject: [options.useExisting || options.useClass!],
};
}
}

View File

@@ -159,7 +159,7 @@ export class FastifyAdapter<
return {
get(version: string | Array<string>) {
if (Array.isArray(version)) {
return versions.get(version.find(v => versions.has(v))) || null;
return versions.get(version.find(v => versions.has(v))!) || null;
}
return versions.get(version) || null;
},
@@ -427,11 +427,11 @@ export class FastifyAdapter<
response.statusCode = statusCode;
return response;
}
return response.code(statusCode);
return (response as TReply).code(statusCode);
}
public end(response: TReply, message?: string) {
response.raw.end(message);
response.raw.end(message!);
}
public render(
@@ -475,7 +475,7 @@ export class FastifyAdapter<
public inject(
opts?: InjectOptions | string,
): LightMyRequestChain | Promise<LightMyRequestResponse> {
return this.instance.inject(opts);
return this.instance.inject(opts!);
}
public async close() {
@@ -539,7 +539,7 @@ export class FastifyAdapter<
}
public getRequestMethod(request: TRequest): string {
return request.raw ? request.raw.method : request.method;
return request.raw ? request.raw.method! : request.method;
}
public getRequestUrl(request: TRequest): string;
@@ -581,7 +581,7 @@ export class FastifyAdapter<
type,
parserOptions,
(
req: RawBodyRequest<FastifyRequest<unknown, TServer, TRawRequest>>,
req: RawBodyRequest<FastifyRequest<any, TServer, TRawRequest>>,
body: Buffer,
done,
) => {
@@ -708,7 +708,7 @@ export class FastifyAdapter<
}
private getRequestOriginalUrl(rawRequest: TRawRequest) {
return rawRequest.originalUrl || rawRequest.url;
return rawRequest.originalUrl || rawRequest.url!;
}
private injectRouteOptions(

View File

@@ -70,7 +70,11 @@ export class WsAdapter extends AbstractWsAdapter {
path?: string;
},
) {
const { server, path, ...wsOptions } = options;
const { server, path, ...wsOptions } = options as {
namespace?: string;
server?: any;
path?: string;
};
if (wsOptions?.namespace) {
const error = new Error(
'"WsAdapter" does not support namespaces. If you need namespaces in your project, consider using the "@nestjs/platform-socket.io" package instead.',
@@ -88,7 +92,7 @@ export class WsAdapter extends AbstractWsAdapter {
}),
);
this.addWsServerToRegistry(wsServer, port, path);
this.addWsServerToRegistry(wsServer, port, path!);
return wsServer;
}
@@ -157,7 +161,7 @@ export class WsAdapter extends AbstractWsAdapter {
if (!message) {
return EMPTY;
}
const messageHandler = handlersMap.get(message.event);
const messageHandler = handlersMap.get(message.event)!;
const { callback } = messageHandler;
return transform(callback(message.data, message.event));
} catch {
@@ -213,8 +217,8 @@ export class WsAdapter extends AbstractWsAdapter {
httpServer.on('upgrade', (request, socket, head) => {
try {
const baseUrl = 'ws://' + request.headers.host + '/';
const pathname = new URL(request.url, baseUrl).pathname;
const wsServersCollection = this.wsServersRegistry.get(port);
const pathname = new URL(request.url!, baseUrl).pathname;
const wsServersCollection = this.wsServersRegistry.get(port)!;
let isRequestDelegated = false;
for (const wsServer of wsServersCollection) {

View File

@@ -59,6 +59,12 @@ export class TestingInjector extends Injector {
metatype: wrapper.metatype,
});
const internalCoreModule = this.container.getInternalCoreModuleRef();
if (!internalCoreModule) {
throw new Error(
'Expected to have internal core module reference at this point.',
);
}
internalCoreModule.addCustomProvider(
{
provide: name,

View File

@@ -160,7 +160,7 @@ export class TestingModuleBuilder {
private getRootModule() {
const modules = this.container.getModules().values();
return modules.next().value;
return modules.next().value!;
}
private async createInstancesOfDependencies(

View File

@@ -16,7 +16,9 @@
"sourceMap": false,
"allowJs": false,
"strict": true,
"strictNullChecks": false,
"strictNullChecks": true,
"forceConsistentCasingInFileNames": true,
"strictPropertyInitialization": false,
"types": ["node"]
}
}

View File

@@ -33,6 +33,6 @@ export class ExceptionFiltersContext extends BaseExceptionFilterContext {
}
public getGlobalMetadata<T extends any[]>(): T {
return [] as T;
return [] as any[] as T;
}
}

View File

@@ -15,9 +15,8 @@ export class WsException extends Error {
) {
this.message = (this.error as Record<string, any>).message;
} else if (this.constructor) {
this.message = this.constructor.name
.match(/[A-Z][a-z]+|[0-9]+/g)
.join(' ');
this.message =
this.constructor!.name!.match(/[A-Z][a-z]+|[0-9]+/g)!.join(' ');
}
}

View File

@@ -21,14 +21,14 @@ export class GatewayMetadataExplorer {
const instancePrototype = Object.getPrototypeOf(instance);
return this.metadataScanner
.getAllMethodNames(instancePrototype)
.map(method => this.exploreMethodMetadata(instancePrototype, method))
.map(method => this.exploreMethodMetadata(instancePrototype, method)!)
.filter(metadata => metadata);
}
public exploreMethodMetadata(
instancePrototype: object,
methodName: string,
): MessageMappingProperties {
): MessageMappingProperties | null {
const callback = instancePrototype[methodName];
const isMessageMapping = Reflect.getMetadata(
MESSAGE_MAPPING_METADATA,

View File

@@ -15,7 +15,7 @@ export class SocketsContainer {
options: T,
): ServerAndEventStreamsHost {
const uniqueToken = this.generateHashByOptions(options);
return this.serverAndEventStreamsHosts.get(uniqueToken);
return this.serverAndEventStreamsHosts.get(uniqueToken)!;
}
public addOne<T extends GatewayMetadata = any>(

View File

@@ -11,12 +11,13 @@ export function createWsParamDecorator(
return (...pipes: (Type<PipeTransform> | PipeTransform)[]) =>
(target, key, index) => {
const args =
Reflect.getMetadata(PARAM_ARGS_METADATA, target.constructor, key) || {};
Reflect.getMetadata(PARAM_ARGS_METADATA, target.constructor, key!) ||
{};
Reflect.defineMetadata(
PARAM_ARGS_METADATA,
assignMetadata(args, paramtype, index, undefined, ...pipes),
target.constructor,
key,
key!,
);
};
}
@@ -29,15 +30,15 @@ export const createPipesWsParamDecorator =
): ParameterDecorator =>
(target, key, index) => {
const args =
Reflect.getMetadata(PARAM_ARGS_METADATA, target.constructor, key) || {};
Reflect.getMetadata(PARAM_ARGS_METADATA, target.constructor, key!) || {};
const hasParamData = isNil(data) || isString(data);
const paramData = hasParamData ? data : undefined;
const paramPipes = hasParamData ? pipes : [data, ...pipes];
Reflect.defineMetadata(
PARAM_ARGS_METADATA,
assignMetadata(args, paramtype, index, paramData, ...paramPipes),
assignMetadata(args, paramtype, index, paramData!, ...paramPipes),
target.constructor,
key,
key!,
);
};

View File

@@ -156,7 +156,7 @@ export class WebSocketsController {
.pipe(
distinctUntilChanged((prev, curr) => compareElementAt(prev, curr, 0)),
)
.subscribe((args: unknown[]) => instance.handleConnection(...args));
.subscribe((args: unknown[]) => instance.handleConnection!(...args));
}
}

View File

@@ -4,6 +4,8 @@
"noImplicitAny": false,
"noUnusedLocals": false,
"removeComments": true,
"strictNullChecks": true,
"strictPropertyInitialization": false,
"forceConsistentCasingInFileNames": true,
"noLib": false,
"emitDecoratorMetadata": true,