typescript interface extends mock - javascript

I have a typescript interface cRequest that's being passed as a type in a class method.
This interface also extends express Request type. What's the correct way to mock this in jest or typemoq?
import { Request } from 'express';
import { User } from '.';
export interface cRequest extends Request {
context: {
ID?: string;
user?: string;
nonUser?: string;
};
user?: User;
}
export default cRequest;
This is being used in a class method as follows
import { Response } from 'express';
public getData = async (req: cRequest, res: Response) => {}
And if i try to test it as follows it fails
const expRespMock: TypeMoq.IMock<Response> = TypeMoq.Mock.ofType<Response>();
const cReqMock: TypeMoq.IMock<cRequest> = TypeMoq.Mock.ofType<cRequest>();
await classObj.getData(cReqMock, expRespMock);
with the following message
Argument of type 'IMock<cRequest>' is not assignable to parameter of type 'cRequest'.
Property 'context' is missing in type 'IMock<cRequest>'.
What's the correct way to inject this interface mock into the method in tests?

I was able to overcome this problem as follows
const cRequestStub= <cRequest> {};
And also it's now possible to selectively inject params as i need without any errors
const cRequestStub= <cRequest> {user: undefined}; or
const cRequestStub= <cRequest> {context: {ID: '', user: '', nonUser: ''}};
await classObj.getData(cRequestStub, expRespMock);

Why to invent the wheel?
Jest has an interface that "decorates" given interface with the additional methods.
For example:
interface IRequest {
req: string;
}
requestMock: jest.Mocked<IRequest>;
requestMock will have the IRequest interface + the mocks interface.
The simplest way to learn about new jest types is to check the source-code of the #types/jest lib, for example I've checked that is the return type of jest.spyOn and from that I've learned about jest.Mocked<>.

Related

MongoDB and class-validator unique validation - NESTJS

TL;DR
I am trying to run mongoose query in my validator
Hello, I am trying to make a custom decorator which throws an error if a value for that field already exists. I am trying to use the mongoose model inside the class that validates the route. Unlike in resolver/controller, #InjectModel() does not work in validator class. My validator is like this
import { getModelToken, InjectModel } from "#nestjs/mongoose";
import {
ValidationArguments,
ValidatorConstraint,
ValidatorConstraintInterface,
} from "class-validator";
import { Model } from "mongoose";
import { User } from "../schema/user.schema";
#ValidatorConstraint({ name: "IsUniqueUser", async: true })
export class UniqueValidator implements ValidatorConstraintInterface {
constructor(
#InjectModel(User.name)
private readonly userModel: Model<User>,
) {}
async validate(value: any, args: ValidationArguments) {
const filter = {};
console.log(this.userModel);
console.log(getModelToken(User.name));
filter[args.property] = value;
const count = await this.userModel.count(filter);
return !count;
}
defaultMessage(args: ValidationArguments) {
return "$(value) is already taken";
}
}
and my DTO that uses the above decorator is
#InputType({})
export class UserCreateDTO {
#IsString()
name: string;
#IsUniqueUser({
message: "Phone number is already taken",
})
#Field(() => String)
phone: string;
}
The console says
cannot read value count of undefined implying that userModel is undefined.
InShort
I want to run the query in my validator. How can I do so?
According to this issue (you can't inject a dependency)
You should to add in your main.ts
import { useContainer } from 'class-validator';
useContainer(app.select(AppModule), {fallbackOnErrors: true});
Then you need to add your UniqueValidator to your module like an #Injectable() class
so
...
providers: [UniqueValidator],
...
Then, in your DTO you can add:
#Validate(UniqueValidator, ['email'], {
message: 'emailAlreadyExists',
})

Class interface in typescript

I am new to typescript and not that familiar.
I was reading this blog on web and trying to comprehend the code
Here the author have created a simple route
// /lib/routes/crmRoutes.ts
import {Request, Response} from "express";
export class Routes {
public routes(app): void {
app.route('/')
.get((req: Request, res: Response) => {
res.status(200).send({
message: 'GET request successfulll!!!!'
})
})
}
}
Which is he is using like this in a kind of main-entry point file
// /lib/app.ts
import * as express from "express";
import * as bodyParser from "body-parser";
import { Routes } from "./routes/crmRoutes";
class App {
public app: express.Application;
public routePrv: Routes = new Routes();
constructor() {
this.app = express();
this.config();
this.routePrv.routes(this.app);
}
private config(): void{
this.app.use(bodyParser.json());
this.app.use(bodyParser.urlencoded({ extended: false }));
}
}
From the definition I read on web, Classes are also like interface in typescript, so this line
public routePrv: Routes = new Routes();
Here, Routes is an interface for routePrv:? And from my vague understanding, interface usually looks like this
interface Person {
name: string;
age: number;
}
So my question is that, How can a class be an interface and how will our interface look like in case of
public routePrv: Routes = new Routes();
Can someone please explain the same?
You are confusing Interfaces and Types.
An Interface (interface MyInterface {}) is used to express what an Object has to look like. After typescript transpilation, interfaces are removed. They are more like "hints" for typescript. An example of its usage is this:
interface MyInterface {
myProp:number;
}
const myConst = {myProp: 0}; // implicitly implements MyInterface
const myConst2:MyInterface = {myProp: 0}; // Explicitly tells typescript the type of "myConst2" should be "MyInterface"
const myConst2:MyInterface = {}; // Error, does not implement "MyInterface" correctly
function myFunc(input:MyInterface) {/* Do something */}
myFunc(myConst); // Works
myFunc(myConst2); // Works
myFunc({}); // Fails
Classes (class MyClass {}) boil down to Constructor Functions. They are a way of constructing an Object. Since they describe how to construct an Object and thus describe the constructed Object's shape, they can also be used to describe the type of an Object. Since Classes are Constructor Functions, they do something during runtime. Hence, only their usages as types are removed.
// You can explicitly implement the interface or explicitly, doesn't matter for its usage.
// Explicitly just tells typescript that this class MUST implement the interface
class MyClass /* implements MyInterface */ {
constructor(public myProp?:number = 0) {}
}
const myClassConst = new MyClass(); // works
const myClassConst2:MyClass = new MyClass(); // works
const myClassConst3:MyInterface = new MyClass(); // works
myFunc(myClassConst); // works
myFunc(myClassConst2); // works
myFunc(myClassConst3); // works
function myFunc2(input:MyClass) { /* Do something */ }
myFunc2(myClassConst); // works
myFunc2(myClassConst2); // works
myFunc2(myClassConst3); // works
As per Request, another example of what does not work:
class MyOtherClass {
constructor(public myProp:number) {}
}
const myOthClassConst = new MyOtherClass(); // works
const myOthClassConst2:MyClass = new MyOtherClass(); // fails, type mismatch
const myOthClassConst3:MyInterface = new MyOtherClass(); // fails, type mismatch
function myFunc3(input:MyOtherClass) {}
myFunc3(myOthClassConst2); // works
myFunc3(myClassConst); // fails, type mismatch
Edit: Rephrased the explanation due to ambigious meaning (thanks to #Bergi for pointing that out).

Typescript error "Property 'then' does not exist" when chaining promises with promise-middleware + thunk

I'm using redux-promise-middleware with redux-thunk in order to chain my promises:
import { Dispatch } from 'redux';
class Actions {
private static _dispatcher: Dispatch<any>;
public static get dispatcher(): Dispatch<any> {
return Actions._dispatcher;
}
public static test() {
this.dispatcher({
type: 'MY_ACTION',
payload: new Promise(resolve => resolve('hi'));
}).then(result => {
console.log(result); // this works
});
}
}
The code above works but also generates a warning during compile time:
TS2339: Property 'then' does not exist on type '{ type: string;
payload: Promise<{}>; }'
It sounds like I need to include Promise<...> somewhere as a type so typescript knows that then is in fact a property on the object that's returned by dispatcher() but I haven't been able to remove the error.
https://github.com/gaearon/redux-thunk/issues/103
import { Dispatch } from 'redux';
import { ThunkAction } from 'redux-thunk';
import { getStore, IState } from './my_store';
let store = getStore();
// Create myThunkAction function with a type of ThunkAction<R, S, E>
let myThunkAction: ThunkAction<Promise<string>, IState, null> =
(dispatch: Dispatch<IState>, getState: () => IState) => {
return new Promise<string>((resolve, reject) => {
// do async stuff with getState() and dispatch(), then...
resolve('done!');
});
}
store.dispatch(myThunkAction)
.then(() => {
// do stuff after the thunk has finished...
});
Seems related but where I can specify the action type i.e. MY_ACTION?
As you can see in this ts playground the variable a exposes the same keys as the type ofDispatch<any>, and as you can see if you mouse over the error, the error message is the same as in your case. In order to access the promise (and there for the then function) you will have to access the payload of the Dispatch object.
this.dispatcher({ ... }).payload.then(....);
Edit1:
If we take a look at the typings for redux we can quite quickly find the Dispatcher interface.
export interface Dispatch<S> {
<A extends Action>(action: A): A;
}
export interface Action {
type: any;
}
And then through some rewriting and some liberal use of psudocode, we can deduct that the type of Dispatch is a function that takes one argument witch is an object and returns an object of the same type as the argument.
type Dispatch: (action: {type: any, ...}) => {type: any, ...}
Both the input object and the output object is of the type:
interface {
type: any,
[key: string]: value
}
In conclusion, either 1) you are not using the official typings for redux, 2) the official typings for redux is wrong, or 3) you have missed something in your live environment were in fact the code doesn't work.
Edit2:
I haven't tried this code, so i have no idea if it will actually solve your problem. But you could try to redefine the Dispatch interface.
declare module 'redux' {
export interface Action {
type: any;
}
export interface Dispatch<S> {
<A extends Action>(action: A): Promise<S>;
}
}
It is valid typescript as you can see in this playground, but I haven't had to do this my self before, so this might not work out of the box.
If that doesn't work you could try defining a namespace with the same name as the module.
namespace redux {
export interface Action {
type: any;
}
export interface Dispatch<S> {
<A extends Action>(action: A): Promise<S>;
}
}
Still I haven't tried this before, so I cant guarantee it will work.

How can I monkey-patch a module in typescript [duplicate]

Consider the following code:
import redis = require('redis'); //Has ambient declaration from DT
import bluebird = require('bluebird'); //Has ambient declaration from DT
bluebird.promisifyAll((<any>redis).RedisClient.prototype);
bluebird.promisifyAll((<any>redis).Multi.prototype);
const client = redis.createClient();
client.getAsync('foo').then(function(res) {
console.log(res);
});
getAsync will error out because it's created on the fly and not defined in any .d.ts file. So what is the proper way to handle this?
Also, even though I have the .d.ts files loaded for redis, I still need to cast redis to any to be used for promisifyAll. Otherwise, it will spill out error:
Property 'RedisClient' does not exist on type 'typeof "redis"'
Is typing it to any the only easy way to go?
I'm solving this by declaration merging the setAsync & getAsync methods. I added the following code in my own custom .d.ts file.
declare module "redis" {
export interface RedisClient extends NodeJS.EventEmitter {
setAsync(key:string, value:string): Promise<void>;
getAsync(key:string): Promise<string>;
}
}
Another way to do it which requires less code is to extend the Redis object like so:
import { promisify } from 'util';
import { ClientOpts, RedisClient } from 'redis';
class AsyncRedis extends RedisClient {
public readonly getAsync = promisify(this.get).bind(this);
public readonly setAsync = promisify(this.set).bind(this);
public readonly quitAsync = promisify(this.quit).bind(this);
public readonly rpushAsync: (list: string, item: string) => Promise<number> = promisify(
this.rpush
).bind(this);
public readonly blpopAsync: (
list: string,
timeout: number
) => Promise<[string, string]> = promisify(this.blpop).bind(this);
public readonly flushdbAsync = promisify(this.flushdb).bind(this);
}
Notice that not all method signatures overwrite correctly, so you have to help typescript a little.
Now you can just use this enhanced class by creating it with your options, for example:
new AsyncRedis({
host: process.env.REDIS_HOST || '127.0.0.1',
password: process.env.REDIS_PASSWORD || 'whatever',
});
Just adding to Dave's answer, in my needs, I has to add in Multi for atomic operations.
declare module 'redis' {
export interface RedisClient extends NodeJS.EventEmitter {
execAsync(...args: any[]): Promise<any>;
hgetallAsync(...args: any[]): Promise<any>;
// add other methods here
}
export interface Multi extends Commands<Multi> {
execAsync(...args: any[]): Promise<any>;
// add other methods here
}
}
This solution works fine for me:
import { promisifyAll } from 'bluebird'; // import here works only if #types/bluebird is installed
import redis, { RedisClient, Multi } from 'redis'; // import here works only if #types/redis is installed
// Convert Redis client API to use promises, to make it usable with async/await syntax
const MultiAsync: any = promisifyAll(Multi.prototype);
const RedisClientAsync: any = promisifyAll(RedisClient.prototype);
const redisAsync = { ...redis, Multi: MultiAsync, RedisClient: RedisClientAsync };
const client: typeof RedisClientAsync = redisAsync.createClient();
// now you can use client async methods, i.e. client.getAsync, client.hgetAsync, client.hsetAsync, client.expireAsync...

How to properly deal with promisifyAll in typescript?

Consider the following code:
import redis = require('redis'); //Has ambient declaration from DT
import bluebird = require('bluebird'); //Has ambient declaration from DT
bluebird.promisifyAll((<any>redis).RedisClient.prototype);
bluebird.promisifyAll((<any>redis).Multi.prototype);
const client = redis.createClient();
client.getAsync('foo').then(function(res) {
console.log(res);
});
getAsync will error out because it's created on the fly and not defined in any .d.ts file. So what is the proper way to handle this?
Also, even though I have the .d.ts files loaded for redis, I still need to cast redis to any to be used for promisifyAll. Otherwise, it will spill out error:
Property 'RedisClient' does not exist on type 'typeof "redis"'
Is typing it to any the only easy way to go?
I'm solving this by declaration merging the setAsync & getAsync methods. I added the following code in my own custom .d.ts file.
declare module "redis" {
export interface RedisClient extends NodeJS.EventEmitter {
setAsync(key:string, value:string): Promise<void>;
getAsync(key:string): Promise<string>;
}
}
Another way to do it which requires less code is to extend the Redis object like so:
import { promisify } from 'util';
import { ClientOpts, RedisClient } from 'redis';
class AsyncRedis extends RedisClient {
public readonly getAsync = promisify(this.get).bind(this);
public readonly setAsync = promisify(this.set).bind(this);
public readonly quitAsync = promisify(this.quit).bind(this);
public readonly rpushAsync: (list: string, item: string) => Promise<number> = promisify(
this.rpush
).bind(this);
public readonly blpopAsync: (
list: string,
timeout: number
) => Promise<[string, string]> = promisify(this.blpop).bind(this);
public readonly flushdbAsync = promisify(this.flushdb).bind(this);
}
Notice that not all method signatures overwrite correctly, so you have to help typescript a little.
Now you can just use this enhanced class by creating it with your options, for example:
new AsyncRedis({
host: process.env.REDIS_HOST || '127.0.0.1',
password: process.env.REDIS_PASSWORD || 'whatever',
});
Just adding to Dave's answer, in my needs, I has to add in Multi for atomic operations.
declare module 'redis' {
export interface RedisClient extends NodeJS.EventEmitter {
execAsync(...args: any[]): Promise<any>;
hgetallAsync(...args: any[]): Promise<any>;
// add other methods here
}
export interface Multi extends Commands<Multi> {
execAsync(...args: any[]): Promise<any>;
// add other methods here
}
}
This solution works fine for me:
import { promisifyAll } from 'bluebird'; // import here works only if #types/bluebird is installed
import redis, { RedisClient, Multi } from 'redis'; // import here works only if #types/redis is installed
// Convert Redis client API to use promises, to make it usable with async/await syntax
const MultiAsync: any = promisifyAll(Multi.prototype);
const RedisClientAsync: any = promisifyAll(RedisClient.prototype);
const redisAsync = { ...redis, Multi: MultiAsync, RedisClient: RedisClientAsync };
const client: typeof RedisClientAsync = redisAsync.createClient();
// now you can use client async methods, i.e. client.getAsync, client.hgetAsync, client.hsetAsync, client.expireAsync...

Categories

Resources