How to use the Lit-Element query decorator? - lit-element

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
}
}

Related

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

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

Adding Swagger decorators to NestJS module for reuse

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?

Nodejs: After Import of a module, code in the file is not getting executed

I am working on few files in nodejs app with typescript
Concerning files are as follows:
some-module.ts
console.log('inside some-module');
export default class Foo {
/*...*/
}
/*execute some imp code*/
Injector.provideClass('Foo', Foo);
console.log('done with some-module');
app.ts
console.log('inside app.ts');
import Foo from './some-module'; // this does not execute console.log! Since Foo class is only referred and not actually used in app.ts file.
class App {
static inject = ['Foo'];
private foo: Foo;
constructor(foo: Foo) {
this.foo = foo;
}
/*...*/
}
Injector.injectClass(App); // This throws error as Foo is not provided in injector.
console.log('Done with app.ts');
Output (console):
$ inside app.ts
$ Done with app.ts
Already tried:
I have tried with const Foo = require('./some-module');, this works but its not the best way to do it in typescript. Since it does not recognize the types in it.
Also -> If if put imported Foo in console.log right after import statement then also it works. Since Foo is now getting used in imported module file.
import Foo from './some-module';
console.log(Foo); // <- After adding this simple log, it works!
Also -> If you do only import import './some-module';
But this way you dont have access to its types.
tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"esModuleInterop": true,
"target": "es6",
"noImplicitAny": true,
"moduleResolution": "node",
"sourceMap": false,
"outDir": "dist",
"baseUrl": ".",
"lib": ["es2015"],
"paths": {
"*": [
"node_modules/*"
]
}
},
"include": [
"src/**/*"
]
}

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;
}

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