Typescript class can only be found if there isn't a reference to its properties? - node.js

I am using TypeScript 2.0 in VSCode, however, the errors highlighted are all confirmed by the TypeScript compiler. So I am importing a module:
import * as els from 'elasticsearch';
where elasticsearch has definitions installed, e.g. npm i #types/elasticsearch -S
Now if in my class I have a property with an els type like this:
private _client: els.Client;
There isn't an issue, however, if I have a property with a type like this:
search(term: string): Promise<els.Client.search> {}
then I get the error:
Module 'Elasticsearch' has no exported member 'Client'
How can the class not be found if I'm looking for one of its properties, but not if I just look for it?

You are right, the error message is confusing. It originates from your attempt to use els.Client.search as a type. You get similar messages if you try this:
import * as els from 'elasticsearch';
class Foo {
private _client: els.Client;
y: els.Client.search;
bar() {}
x: Foo.bar;
}
error TS2305: Module 'Elasticsearch' has no exported member 'Client'.
error TS2503: Cannot find namespace 'Foo'.
Note how in the second message it complains that it can't find Foo right within the Foo class. You might consider posting an issue for typescript about this.
How can the class not be found if I'm looking for one of its
properties, but not if I just look for it?
The real problem is that you probably want the return type of your search to be the same as the return type of els.Client.search. I don't think there is a better way to do that other than essentially copy els.Client.search declaration:
search<T>(term: string): Promise<els.SearchResponse<T>> {}

Related

Typescript - Dynamic class Type

I'm trying to build a sort of model Factory in Typescript.
I'm receiving a string parameter from an API call and I would like to istantiate a new object depending on the received value.
Here you can find a simple example of what I would like to accomplish:
/classes/ClassA.ts
export class ClassA {
doSomething() {
console.log("ClassA");
}
}
/classes/ClassB.ts
export class ClassB {
doSomething() {
console.log("ClassB");
}
}
/classes/index.ts
import { ClassA } from './ClassA';
import { ClassB } from './ClassB';
export { ClassA, ClassB }
Now, I would like to import all classes exported from index.ts (this file will be automatically updated when a new Class is being created) and run doSomething() on a class depending on a variable value:
/index.ts
import * as Classes from './classes';
const className: string = "ClassA";
new Classes[className]().doSomething()
In visualStudioCode I don't get any error, but at compile time I get:
error TS7053: Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'typeof import("/testApp/src/tmp/classes/index")'.
Even changing className to "any" gives the same result.
If I remove className type
const className = "ClassA";
it works without any issue but I cannot proceed in this direction because received value is "typed" as string.
I know that prepending istantiation code with
// #ts-ignore
It works but I would like to avoid this kind of "tricks"
So, what would it be the correct way to type className getting it's possible values from the imported ts?
Thanks
Micko

Compiler error on using namespace's parameterized constructor of a class

I want to initialize a class present in Typescript's namespace. This class has a parameterized constructor, but when I tried to use this class then compiler complains about it and I cannot use this class for instantiation.
**Inside file tv.dto.ts**
export namespace tv{
export class Trial{
private name:string;
Trial(name:string){
this.name=name;
}}}
Inside my other Jest class file.
import { tv } from "./tv.dto";
import {Graph} from 'graphlib';
describe('testing',()=>{
it('TestCase1',() =>{
let k=new tv.Trial("WonderFulName");// It flags compiler error here.
console.log(JSON.stringify(k));
});
});
Error message which I received was "TS2554: Expected 0 arguments, but got 1."
Screenshot for the same.
Please help me in resolving this issue.
Edit:
I am able to resolve this issue by importing properly:
import {tv as tv} as './tv.dto'
Don't export the namespace, instead just keep the export of Trial. Then import that instead from the same file reference.
Edit: Alternatively, change the constructor to use the word "constructor" instead of the class name.

"as" notation with TypeScript, need to export a namespace?

I have this TypeScript code:
import * as suman from 'suman';
const Test = suman.init(module,{
ioc: {
a: 'foo',
b: 'far'
} as suman.Ioc
});
As you can see I am trying to declare that the ioc object has a type of suman.Ioc (ioc object should "adhere to the Ioc interface"). But my IDE says "cannot find namespace 'suman'".
How can I create a type and reference it in my code in this scenario? I'd like to be able to reference the Ioc object type from the suman import if possible.
In other words, I don't want to do this all in the same file:
declare namespace suman {
interface Ioc {
a: string,
b: string
}
}
import * as suman from 'suman';
const Test = suman.init(module,{
ioc: {
a: 'foo',
b: 'far'
} as suman.Ioc
});
the reason is because I would then have to repeat the namespace declaration for every file like this which shouldn't be necessary (or advised).
suman is typed but the typed version is not release yet.
For now, you can installing it by npm install sumanjs/suman if you are comfortable to use the latest code.
If you want to use the latest release AND use the typings, you can consider using typings to install the typings file: typings install suman=github:sumanjs/suman/lib/index.d.ts and include typings/index.d.ts in your tsconfig.json.
As for as suman.Ioc, it is a way to tell the compiler that "hey, I know that you think this 'thing' is of some other type, but I would like you to treat it as 'suman.Ioc'".
That's why, even if the typings is there, it will not do what you wanted.
Luckily, the typings supplied by suman will be working fine for you.

TypeScript Cannot find namespace despite Variable being in same Class

I'm trying to define Callbackdefinitions to make it easier to work with many callbacks in my Node.js project.
My database.ts file looks like that:
export default class Database {
//Export the enums
public static LoadObjectResponse = LoadObjectResponse;
//Export Callback definitions
public static loadObjectCallback: (resultCode: Database.LoadObjectResponse) => void;//ERROR
...
}
enum LoadObjectResponse {
ERROR_ON_LOADING, //"Error on Loading Object.",
OBJECT_NOT_FOUND //"Object not found."
}
So I want a loadObjectCallback defined, that says that the parameter has to be of the enum Type LoadObjectResponse. But when I try to do it like that, the compiler always gives the error
Cannot find namespace "Database"
I don't understand why it gives me the error, the variable itself is in the definition of Database, why doesn't it work?
It gives me the same error when I try to use it in Classfunction definitions:
public static loadObject(MongoModel, searchObject, callback: Database.LoadObjectResponse) {//ERROR namespace Database not found
Again Error:
Cannot find namespace "Database"
Inside of functions in the Database class calling
Database.LoadObjectResponse
works flawlessly, why doesn't it work in variable definitions?
Cannot find namespace "Database"
This is a common learning curve issue. You need to understand and be comfortable with the intutive concept of declaration spaces : https://basarat.gitbook.io/typescript/project/declarationspaces
Things are distinct in the type declaration space or in the variable declaration space.
In your case public static LoadObjectResponse is a variable hence cannot be used as a type (error on annotation usage : Database.LoadObjectResponse).
Fix
Please don't treat a class as a namespace. The file is a module.
export class Database {
//Export Callback definitions
public static loadObjectCallback: (resultCode: LoadObjectResponse) => void;//ERROR
}
export enum LoadObjectResponse {
ERROR_ON_LOADING, //"Error on Loading Object.",
OBJECT_NOT_FOUND //"Object not found."
}
Also beware of export default : https://basarat.gitbook.io/typescript/main-1/defaultisbad
It's because Database.LoadObjectResponse is a property and not a type. You can't use properties as types.
To make this work, change it to use the type of the property:
static loadObjectCallback: (resultCode: typeof Database.LoadObjectResponse) => void;
Or refer directly to the enum type of LoadObjectResponse:
static loadObjectCallback: (resultCode: LoadObjectResponse) => void

Can't use a Doctrine repository as user provider

I'm trying to create a custom user provider.
I defined my UserProvider as a service:
myvendor.user_provider:
class: MyVendor\UserBundle\Service\Security\UserProvider
This class is a DocumentRepository:
namespace MyVendor\UserBundle\Service\Security;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Doctrine\ODM\MongoDB\DocumentRepository;
use Doctrine\ODM\MongoDB\DocumentNotFoundException;
class UserProvider extends DocumentRepository implements UserProviderInterface {
//public function loadUserBy...
}
But I get this error:
Catchable Fatal Error: Argument 1 passed to Doctrine\ODM\MongoDB\DocumentRepository::__construct() must be an instance of Doctrine\ODM\MongoDB\DocumentManager, none given, called in /home/www/dev/public/myapp/app/cache/dev/appDevDebugProjectContainer.php on line 258 and defined in /home/www/dev/public/myapp/vendor/doctrine/mongodb-odm/lib/Doctrine/ODM/MongoDB/DocumentRepository.php line 68
Seems like the document manager has not been created yet at that point, because I also tried injecting it, but it complains about its own dependencies, like the UnitOfWork.
What can I do?
The service definition was tricky
myvendor.user_provider:
class: MyVendor\UserBundle\Service\Security\UserProvider
factory_service: doctrine.odm.mongodb
factory_method: getRepository
arguments: [ 'MyVendorUserBundle:User\User' ]

Resources