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
Related
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
I'd like to create a shared library for reuse in a related Express NestJS app. In order to do so and gain type introspection + examples on nested objects in the input/output, I am struggling to maintain information from the imported package that works just fine.
Here's a sample of my efforts that work locally when I pass in this class directly on the controller. However, when running this from a file that has only this exported, I lose the examples + introspection. I believe there is either an error in my typescript build that is causing metadata/decorators to be cut out, or there is a problem in my nest build in the api file, that causes the types to be lost.
My typed response classes (abbreviated) are here (identical when in the file or imported):
export class ExtendedRelatedSubClass extends RelatedSubClass {
private static exampleSubClass: RelatedSubClass = getRelatedSubClassMock()
#ApiProperty({ example: ExtendedRelatedSubClass.exampleSubClass.randomProp })
public randomProp: string
}
export class ExtendedUserResponse extends UserResponse {
private static exampleUser: UserResponse = getUserMock()
#ApiProperty({ example: ExtendedAccountHolderResponse.exampleAccountHolder.address })
public address: ExtendedAddressResponse = new ExtendedAddressResponse()
#ApiProperty({ example: ExtendedAccountHolderResponse.exampleAccountHolder.legalInformation })
public relatedSubClass: ExtendedRelatedSubClass = new ExtendedRelatedSubClass()
}
The class is then used on a controller like so:
export const userFilteredProps = [
'randomSubClass',
] as const
export class FilteredUserResponse extends PickType(
ExtendedUserResponse,
userFilteredProps
) {}
#Controller('/:market/users')
export class UsersController {
constructor(protected readonly userService: UserService) {}
#Get('/')
#HttpCode(200)
public async getUser(
#Param() params: MarketParam,
): Promise<FilteredUserResponse> {
}
My attempt at creating an external module does not maintain this integrity of the examples/decorators and has this tsconfig (I completely lose typing and examples when it is imported into the old file):
{
"compilerOptions": {
"module": "commonjs",
"declaration": true,
"removeComments": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"target": "es2017",
"sourceMap": true,
"outDir": "./dist",
"baseUrl": "./",
"incremental": true,
"skipLibCheck": true
},
"include": ["src/**/*"]
}
My nest-cli file for swagger:
{
"collection": "#nestjs/schematics",
"sourceRoot": "src",
"entryFile": "create-swagger-app",
"compilerOptions": {
"plugins": [{
"name": "#nestjs/swagger",
"options": {
"controllerFileNameSuffix": ".controller.ts",
"classValidatorShim": true,
"dtoFileNameSuffix": [".response.ts", ".request.ts"]
}
}]
}
}
Are there any issues with how the file is being exported from the package? I have tried both nest build and yarn build with no success.
Could there be more parameters in my nest cli swagger build that are needed as well?
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;
}
Code fails Typescript compilation when attempting to use the Lit-Element query decorator.
With tsconfig.json
{
"compilerOptions": {
"target": "es2017",
"module": "es2015",
"moduleResolution": "node",
"lib": ["es2017", "dom"],
"outDir": "../../out/client",
"allowJs": true,
"experimentalDecorators": true
}
}
and package.json
"dependencies": {
"lit-element": "^2.2.1"
},
tsc command yields the following error:
Unable to resolve signature of property decorator when called as an expression.
Type '{ kind: string; placement: string; key: any; descriptor: any; }' is not assignable to type 'void'.
However, if I comment out the two lines of the decorator, and un-comment the equivalent get function, no errors.
#customElement("my-app")
export default class extends LitElement {
#query("p")
p: any;
// get p() {
// return this.shadowRoot.querySelector("p");
// }
render() {
return html`
Hello World!
<p>A paragraph</p>
`;
}
I expected identical behavior using either the query decorated property or the property getter.
Do you correctly import the query annotation?
The following element works for me:
/**
* Import LitElement base class, html helper function,
* and TypeScript decorators
**/
import {
LitElement, html, customElement, query
} from 'lit-element';
#customElement("my-app")
export default class extends LitElement {
#query("p")
p: any;
// get p() {
// return this.shadowRoot.querySelector("p");
// }
render() {
return html`
Hello World!
<p>A paragraph</p>
`;
}
}
With a tsconfig.json:
{
"compilerOptions": {
"moduleResolution": "node",
"module": "es6",
"target": "es6",
"experimentalDecorators": true
}
}
While using the new TypeScript feature, so called ES Dynamic Imports, I am not able to run the code of my isomorphic app on the server side using ts-node.
It seems like the error does not occur when using the webpack module loader which transpiles the code in it's own way and running resulting files in a browser.
The error which I've got:
case 0: return [4 /*yield*/, import("./component/main")];
^^^^^^
SyntaxError: Unexpected token import
Usually TypeScript transpiles the import expression to something like that: Promise.resolve(require("./component/main")), but I can't see it there.
How to fix that? Does it have something common with ts-node? Or there is a "polyfill" for node.js?
My tsconfig.json file:
{
"compilerOptions": {
"declaration": false,
"emitDecoratorMetadata": true,
"allowJs": false,
"experimentalDecorators": true,
"importHelpers": true,
"inlineSourceMap": false,
"inlineSources": false,
"lib": [
"DOM",
"ES5",
"ES6",
"ES7"
],
"listFiles": false,
"module": "commonjs",
"noEmitOnError": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"preserveConstEnums": false,
"pretty": false,
"removeComments": false,
"strict": true,
"target": "es5"
}
}
the code:
import * as m from "mithril";
import LayoutComponent from "./component/layout";
const render = (
layout: m.ComponentTypes<any, any>,
) => ({ tag, attrs }: m.Vnode<any, any>) => m(layout, attrs, m(tag as any, attrs));
export default {
"/:path...": {
onmatch: async (args, path) => (await import("./component/main")).default,
render: render(LayoutComponent),
},
} as m.RouteDefs;
This is a bug in the Typescript Compiler which will be fixed in 2.5.
Exporting a default object with a function that imports a file will not compile the import statement into a require statement in Typescript 2.4.x.
For example, while this:
export const sudo = { run() { return import('./test3'); } }
Will compile to this:
exports.sudo = { run: function () { return Promise.resolve().then(function () { return require('./test3'); }); } };
This:
export default { run() { return import('./test3'); } }
Compiles into this:
exports.default = { run: function () { return import('./test3'); } };
Which is obviously wrong. A temporary solution would be this:
export const sudo = { run() { return import('./test3'); } }
export default sudo;
Which compiles (correctly) into this:
exports.sudo = { run: function () { return Promise.resolve().then(function () { return require('./test3'); }); } };
exports.default = exports.sudo;