Unable to resolve signature of class decorator when called as an expression when using class and method decorators - node.js

i have user class and im attempting to declare a class and method decorator. However im getting the following errors:
error TS1238: Unable to resolve signature of class decorator when
called as an expression. This expression is not callable.
Type 'void' has no call signatures.
1 #OpenAPIPaths({ path: "Users" })
error TS1241: Unable to resolve signature of method decorator when
called as an expression. This expression is not callable.
Type 'void' has no call signatures.
7 #OpenAPIFunction({ Request: {}, Response: {} })
user.controller.ts
#OpenAPIPaths({ path: "Users" })
export class UserController {
constructor() {
console.log("init");
}
#OpenAPIFunction({ Request: {}, Response: {} })
getUser(id: string) {
return id;
}
}
function OpenAPIPaths(other: any): void {
console.log("class", other);
}
function OpenAPIFunction(here: any): void {
console.log("function", here);
}
tsconfig.js
{
"extends": "./tsconfig.paths.json",
"compilerOptions": {
"lib": ["ESNext"],
"moduleResolution": "node",
"noUnusedLocals": false,
"noUnusedParameters": false,
"removeComments": true,
"sourceMap": true,
"target": "ES2020",
"outDir": "dist",
"esModuleInterop": true,
"strictNullChecks": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true
},
"include": ["./**/*.ts"],
"exclude": ["node_modules/**/*", ".serverless/**/*", ".webpack/**/*", "_warmup/**/*", ".vscode/**/*"],
"ts-node": {
"require": ["tsconfig-paths/register"]
}
}
node:16
typescript: 4.9.3

Related

How to extend express.Request with tsserver + JSDoc?

I've using tsserver with JSDoc in vim on a JavaScript project. I've run up against the following problem:
/** #type {import('express').Handler} */
function requireUser(req, res, next) {
if (!req.user) {
throw new Error("Unauthorized");
}
next();
}
Here's the error:
[tsserver] Property 'user' does not exist on type 'Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>'. [E]
Of course, there are hundreds of places in my code where req.user is referenced.
Here's my current tsconfig.json, for reference:
{
"compilerOptions": {
"target": "es2021",
"module": "commonjs",
"allowJs": true,
"checkJs": true,
"noEmit": true,
"strict": true,
"alwaysStrict": true,
"noUnusedLocals": true,
"typeRoots": ["./#types", "./node_modules/#types"],
"esModuleInterop": true,
"preserveSymlinks": false,
"maxNodeModuleJsDepth": 20,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*.js"],
"exclude": ["node_modules"]
}
I've tried putting a file in ./#types/types.d.ts with the whole namespace Express bit for Typescript Declaration Merging, but it doesn't seem to be taking effect.
The full explanation is here:
https://github.com/BeyondCodeBootcamp/jsdoc-typescript-starter
In short:
tsconfig.json:
{
"compilerOptions": {
"typeRoots": ["./typings", "./node_modules/#types"],
"...": ""
},
"...": ""
}
./typings/express/index.d.ts:
// You can extend other types that you modify with middleware.
declare namespace Express {
// Here we tell the linter to expect `user`, `authn`, and `query`
// to exist on Request objects, and a custom `result` handler to
// exist on Response objects.
export interface Request {
query: Record<string, string>;
user?: User;
authn?: any;
}
// Here we tell the linter about our special alternative to
// res.result
export interface Response {
result?: (result: any) => void;
}

ES2017 NEST JS #IsEmpty Unable to resolve signature of property decorator when called as an expression.This expression is not callable. is not empty

Hi people im newer with Nest JS and i trying to add dto validator but for example when i tried to add isNotEmpty or Max compiler show me this error:
Unable to resolve signature of property decorator when called as an
expression. This expression is not callable.
DTO:
import { Transform, Type } from 'class-transformer';
import { IsInt, isNotEmpty } from 'class-validator';
export class MessagesQueryDTO {
#isNotEmpty()
#IsInt()
#Type(() => Number)
readonly limit: number;
#isNotEmpty()
#Type(() => Number)
#IsInt()
readonly skip: number;
}
My config.json
{
"exclude": ["**/*spec.ts"],
"compilerOptions": {
"module": "commonjs",
"declaration": true,
"removeComments": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"target": "es2017",
"sourceMap": true,
"outDir": "./dist",
"baseUrl": "./",
"incremental": true,
"esModuleInterop": true,
}
}
The isNotEmpty decorator should be IsNotEmpty with the first letter in uppercase.
To expand on Juan's answer, isNotEmpty is the internally used check from class-valdiator and can be used as a direct method. IsNotEmtpy (notice the capitalization) is the decorator, and should be used with # to denote it as a decorator.

Typescript - My property decorator isn't working, why?

I'm trying to construct custom decorators, for example, a decorator to validate the minimum length of a string.
function Min(limit: number) {
return function (target: Object, propertyKey: string) {
let value: string;
const getter = function () {
return value;
};
const setter = function (newVal: string) {
if (newVal.length < limit) {
Object.defineProperty(target, 'errors', {
value: `Your password should be bigger than ${limit}`
});
}
else {
value = newVal;
}
};
Object.defineProperty(target, propertyKey, {
get: getter,
set: setter
});
}
}
In the class, I'm calling this way:
export class User {
#Min(8)
password: string;
}
However, I'm getting this exception:
tslib_1.__decorate([
^
ReferenceError: Min is not defined
at Object.<anonymous>
My tsconfig.json:
{
"compilerOptions": {
"module": "commonjs",
"declaration": true,
"removeComments": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"importHelpers": true,
"target": "es2017",
"sourceMap": true,
"outDir": "./dist",
"baseUrl": "./",
"incremental": true
},
"exclude": [
"node_modules",
"dist"
]
}
PS: I know there are libraries, for data validations, like the class-validator, however, I would like to create custom decorators for validations and other features.
Where am I going wrong?
It looks like you forgot to import your decorator. Assuming your structure as following:
- decorator.ts
- index.ts
In decorator.ts:
export function Min(limit: number) {
// ...
}
In the index.ts:
// Don't forget to import your decorator here
import { Min } from './decorator';
export class User {
#Min(8)
password: string;
}

Why Occured Property 'user' does not exist on type 'Request<ParamsDictionary, any, any, Query>'

I am getting the following error when running ts-node.
I defined d.ts as follows to use "req.user" and applied tsconfig.json.
Path: src/#types/express/index.d.ts
import { User } from '../../model/user/user.interface';
declare global {
namespace Express {
interface Request {
user?: User['employeeId'];
}
}
}
tsconfig.json
{
"compilerOptions": {
"typeRoots": [
"./node_modules/#types",
"./src/#types"
],
"rootDir": ".",
"module": "CommonJS",
"strict": true,
"outDir": "dist",
"baseUrl": "./src",
"paths": {
"*": ["node_modules/#types/*", "src/#types"]
},
"esModuleInterop": true
},
"include": ["src/**/*.ts"]
}
controller
Path: src/api/posts/controller.ts
export const get = (req: Request, res: Response) => {
...
const { user } = req;
-> occrud Error
};
What am I missing?
The issue is that ts-node is not picking up your type extensions, but tsc is able to. The relevant GitHub Issue has more details but the TL;DR is that you have to put your custom types before the node_modules/#types ie:
"typeRoots": [
"./src/#types",
"./node_modules/#types"
]
paths is also not needed, so you can probably remove that (it's wrong anyway).
{
"compilerOptions": {
"rootDir": "./src",
"module": "CommonJS",
"strict": true,
"outDir": "./dist",
"baseUrl": "./node_modules",
"paths": {
"*": ["./#types/*","./*", "../src/#types"]
},
"esModuleInterop": false,
"types": ["node", "express"]
},
"include": ["src/**/*.ts"]
}
let's npm -D install #types/node #types/express
now let's create a class controller
import { Request, Response, NextFunction } from "express";
export type EndPointResponse = Promise<Response>;
export class ListController {
public constructor () {
this.getAll = this.getAll.bind(this);
this.getById = this.getById.bind(this);
}
public async getAll (req: Request, res: Response, next: NextFunction): EndPointResponse {
}
public async getById (req: Request, res: Response, next: NextFunction): EndPointResponse {
}
here you have complete explanation https://medium.com/#enetoOlveda/use-sequelize-and-typescript-like-a-pro-with-out-the-legacy-decorators-fbaabed09472

TypeDI #Inject() doesn't work, but Container.get() does

I'm facing weird issue,
Container.get(MyServiceName); returns demanded service, yet class property decorated with #Inject() is undefined.
I've tried decorate class with #Service()
I do import reflect-metada at entry point of my application
import 'reflect-metadata';
I'm wondering if it may be related to fact, that that I'm using typedi not directly from my node_modules but from my dependency?
Application doesn't use Express framework neither routing controllers
My tsconfig.json:
"compilerOptions": {
"declaration": true,
"pretty": true,
"esModuleInterop": true,
"target": "esnext",
"noImplicitAny": true,
"noImplicitReturns": true,
"noUnusedLocals": false,
"moduleResolution": "node",
"noUnusedParameters": true,
"strictPropertyInitialization": false,
"module": "commonjs",
"lib": ["dom", "es2018"],
"importHelpers": true,
"outDir": "./dist",
"strict": true,
"typeRoots": ["node_modules/#types"],
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"sourceMap": true
},
"include": ["./src/**/*"],
"exclude": ["node_modules", "./dist/**/*"]
}
Service that I want to be injected
import MyServiceName from '../services/MyServiceName';
import { Container, Inject, Service } from 'my_dependency/lib';
export default class SomeClass{
#Inject()
private readonly someService: MyServiceName;
public async someMethod(): SomeResponseType {
const thatWorks = Container.get<MyServiceName>(MyServiceName);
console.log(this.someService); // undefined
console.log(thatWorks); // proper class
}
}
Service I want to inject
#Service()
export default class MyServiceName {
public async someMethod(): SomeReturnType {
return someReturnedData;
}
}
I would like to inject my dependencies though #Inject() decorator
You need to create your instance of SomeClass using Container#get, or the container won't be able to inject the property.
This worked for me:
// a.ts
import { Service } from "typedi";
#Service()
export class Foo {
foo() {
return 10;
}
}
// b.ts
import { Foo } from "./a";
import { Inject } from "typedi";
export class Bar {
#Inject() private readonly service: Foo
foo() {
console.log(this.service);
}
}
// test.ts
import "reflect-metadata";
import { Bar } from "./b";
import { Container } from "typedi";
const noFoo = new Bar();
noFoo.foo(); // yields undefined
const withFoo = Container.get<Bar>(Bar);
withFoo.foo(); // yields Foo

Resources