Using Node-Geocoder with Typescript - node.js

I am trying to use Node-Geocoder in my typescript application, using the DefinitelyTyped type definitions found here. What I am wondering is how I am supposed to pass my configuration options to the Node-Geocoder instance. I would think you use it similar to how you use the library in Javascript, by passing the options to the constructor of the Geocoder object. However, that is giving me an error stating that the constructor does not take any arguments.
import DomainServiceInterface from "./../DomainServiceInterface";
import NodeGeocoder from "node-geocoder";
import LocationServiceInterface from "./LocationServiceInterface";
export default class LocationService implements DomainServiceInterface, LocationServiceInterface {
private geocoder: NodeGeocoder.Geocoder;
constructor() {
const options: NodeGeocoder.BaseOptions = {
provider: "google",
// other options
};
this.geocoder = new NodeGeocoder.Geocoder(options);
}
// other methods here
}
I attempted to look this up. However, all tutorials and content I could find related to Node-Geocoder are in Javascript.
What am I doing wrong?

Fair warning, I've never used the node-geocoder package.
If you look at the type definitions, the export is a function, not a class. (Technically declaration merging is used to export a function and a namespace.) That function takes Options and instantiates a Geocoder instance.
That said, you would create a Geocoder like this.
import * as NodeGeocoder from 'node-geocoder';
const options: NodeGeocoder.Options = {
provider: "google",
};
const geoCoder = NodeGeocoder(options);

Related

sinonjs - stub a library referenced internally as a function using node modules (no require)

I have an external library that is exported as a function, in the Stub documentation it only accepts an input with the first parameter as object and the second parameter as method , so how could I stub a library that is exported as a function in a Node ES Modules environment (without Commonjs)?
(In my specific case, I had used a library that use the internet to work, and I wanted to test derivated functions without accessing the internet, so I want to stub the external function library)
Attempts:
I couldn't use solutions like proxyquire as it is a solution based on require and module cache deletion, which are not supported within Node's ES modules.
I don't want to use proxyquire-universal because it simulates the operation of require in normal ES, and it's just a function in the whole project that I wanted to test, I was looking for a simpler solution
Changing the import mode doesn't work as it's not recompiled like in babel, so even if I import as import * as obj from 'lib' only the function name is changed
I had this error environment with 3 files:
An external library called "sum" for example, which I don't want to change, exported as follows:
External Library: externalSum.js
module.exports = function sum(a, b){
console.log(">>>>> running without stub <<<<<")
return a + b
}
This library used in the middle of a project file called mathProblems
Internal File: mathProblems.js
import sum from 'externalSum'
export function sumMore1(a) {
return sum(a, 1);
}
And I have a test file
Internal File: spec.js
import sinon from 'sinon'
import assert from 'assert'
import sumObj from 'externalSum'
import { sumMore1 } from '../mathProblems.js'
describe('sumMore1 is working', () => {
it('sumMore1 test', () => {
const sum_stub = sinon.stub(sumObj) // NOT STUBBING
sum_stub.withArgs(1, 1).returns(2) // NOT STUBBING
const result = sumMore1(1)
assert.strictEqual(result, 2)
});
});
I didn't find this solution anywhere on the internet, i found some solutions that work for node with request or babilon, but not for my case using ES Modules:
https://github.com/sinonjs/sinon/issues/562
https://minaluke.medium.com/how-to-stub-spy-a-default-exported-function-a2dc1b580a6b
So I wanted to register the solution in case anyone needs it.
To solve this, create a new file, which can be allocated anywhere in the project, in this case I will call it sumImport.js:
Internal File: sumImport.js
import sum from 'externalSum';
// export as object
export default {
sum
}
The object needs to be called inside the created function I want to test, and changed the import way:
Internal File: mathProblems.js
import sumObj from './sumImport.js';
export function sumMore1(a) {
const { sum } = sumObj;
return sum(a, 1);
}
And I finally managed to import as an object in the test:
Internal File: spec.js
import sinon from 'sinon'
import assert from 'assert'
import sumObj from '../sumImport.js'
import { sumMore1 } from '../mathProblems.js'
describe('sumMore1 is working', () => {
it('sumMore1 test', () => {
const sum_stub = sinon.stub(sumObj, "sum") // STUBBED
sum_stub.withArgs(1, 1).returns(2) // STUBBED
const result = sumMore1(1)
assert.strictEqual(result, 2)
});
});
I hope it helps someone and if someone else has some better solutions I would also be grateful!

How can I use packages that extend `koa.Request` in TypeScript?

I am trying to use koa-tree-router and koa-bodyparser at the same time, but I keep getting TypeScript errors:
export const userLoggingRouter = new KoaTreeRouter<any, DefaultContext>();
userLoggingRouter.post('/logs/action', (ctx) => {
const logEntries = ctx.request.body;
const user = ctx.state.user;
// ...
});
error TS2339: Property 'body' does not exist on type 'Request'.
I have #types/koa-bodyparser installed, and it contains the following definition:
import * as Koa from 'koa';
declare module 'koa' {
interface Request {
body: string | Record<string, unknown>;
rawBody: string;
}
}
But it doesn't seem to do anything. I found this question, but importing koa-bodyparser directly also does not do anything. How do I get TypeScript to recognize the extended Request type?
Edit: Creating a .d.ts file inside my project containing the following:
import {Request} from "koa";
declare module "koa" {
interface Request {
body: any;
}
}
Made the compile error go away, but this seems like an inelegant solution because I would have to copy over type information for every package that modifies koa.Request.
This was happening because I was using Yarn PnP and I had two different versions of #types/koa installed. Once I added a resolutions field to my package.json that forced all of the other TypeScript definitions to use the same version of #types/koa, everything worked.

How do I find the names of classes in modules for TypeScript

So in this code:
import * as fs from "fs"
class FsAsyncFactory {
private static fsSync: any
}
export default FsAsyncFactory
I've put the type of this prop private static fsSync: any as any but it's going to be the fs variable imported at the top - how do I figure out what the class is called?
I guessed something like FileSystem but it didn't work. I don't have a deep enough understanding of TypeScript to figure it out.
I have "#types/node": "^8.0.50", in my dev dependencies and I've gone into node_modules/#types/node/index.d.ts but I can't see anything that quite makes sense? Thanks!
You can use the "type of" command of typescript.
import * as fs from "fs"
class FsAsyncFactory {
private static fsSync: typeof fs
}
export default FsAsyncFactory
And then inside your class
constructor(){
//...//
FsAsyncFactory.fsSync. //ide recognizes fsSync is of type "fs" and gives you full prediction of fs functions
//...//
}
Question: What is this typeof and why cant I use just class names?
Basically as I understand by reading the node/index.d.ts the fs is just a module that is being exported. Basically an object with some typed functions with their own documentation. In that case we don't have a class name or an interface to declare our other variables which are equal to fs. The typeof command of typescript is a type query, basically if no class or interface is implemented on the source variable it will just expect the same properties of the source to be presented in the target.
Another approach with your issue could be the use of Type Aliases
import * as fs from "fs"
type FileSystem = typeof fs
class FsAsyncFactory {
private static fsSync: FileSystem
}
export default FsAsyncFactory
This will create a new type called FileSystem which will expect every object which is declared as FileSystem type, to implement every function of the fs module.
Question: How can I use Bluebird's promisifyAll with typescript?
import * as fs from "fs"
import * as Bluebird from "bluebird"
const fsProm : FileSystem = Bluebird.promisifyAll(fs)
fsProm.writeFile('filename','some data') // Typescript error function expects at least 3 parameters
.then(console.log)
Unfortunately, from my point of view promisifyAll will change a strict typed function to something else without leaving any definitions of what changed, that is very bad for typescript. After some search I couldn't find any solid solution that will work on all cases, check this issue.
Maybe your best bet is to declare your promisidied variable to type any and continue working without intellisense.

graphql-tag/index has no exported member 'gql'

I'm converting my Angular app REST backend to GraphQL. I'm trying to import gql from graphql-tag. I'm searching and searching and my import looks like everyone elses...
import { Angular2Apollo } from 'angular2-apollo';
import { ApolloClient } from 'apollo-client';
import { gql } from 'graphql-tag';
But the gql has the red underline indicating not found. When i run ng serve I get this error in cmder...
... /node_modules/graphql-tag/index"' has no exported member 'gql'.)
I have run many, many apollo and angular npm installs, including npm install --save graphql-tag, trying install whatever I'm missing, doesn't seem to matter what I install.
What am I doing wrong?
Use the default export instead:
import gql from 'graphql-tag';
I see it. What is happening here is your code is trying to destructure gql off of the object that is exported out of graphql-tag, but the error is telling you there is no exported member of this name, meaning the exported object doesn't have a method of that name, or there are more than one object exported.
If you were to look in the code for graphql-tag, you would see it probably has a few export objects or it only has one that doesnt have a method called gql, so what you need to do is take gql directly, ie: without destructuring it, ie: without the { }.
This will be correct: import gql from 'graphql-tag'
You can see this all the time depending how you export and import things from modules.
Commit to memory that every time you see { something }, it is pulling something off an object.
Here is some sample code to illustrate:
const object = {
test: { name = 'Locohost' }
}
const { name } = object.test
console.log(name)

Can I use a custom module resolution function (like "proxyquire") in place of require() with TypeScript?

I have a TypeScript file config.ts that will be run with node:
import myDependency = require('my-dependency');
export = {
doSomething = () => {
...
}
}
In other TypeScript file, I can import this file with full type safety:
import config = require('./config');
config.doSomething();
config.doSomethingElse(); // compiler error, this method doesn't exist
Now I want to unit test this script. In order to mock out the dependencies that this script require()s I'm using proxyquire, which lets me provide the values that my script will get when it makes calls to require(). Here's what my test might look like:
import proxyquire = require('proxyquire');
const config = proxyquire('./config', {
'my-dependency': {} // this mocked object will be provided when config.ts asks for `my-dependency`
});
expect(config.doSomething()).to.do.something();
This works fine, except that my config variable is of type any because I'm using proxyquire() in place of require(). TypeScript must give the require() function special treatment to allow it to perform module resolution. Is there a way to tell the TypeScript compiler that proxyquire() should also do module resolution, similar to require()?
I could rewrite config.ts as a class or make it use an interface. Then I would be able to explicitly type the variables in my tests by importing the class/interface definition. But allowing proxyquire() to implicitly type things for me would be far be the easier solution.
There is a workaround - you can get the type of config.ts module by importing actual module and using typeof in a type cast:
import proxyquire = require('proxyquire');
import configType = require('./config');
const config = <typeof configType> proxyquire('./config', {
'my-dependency': {} // this mocked object will be provided when config.ts asks for `my-dependency`
});
config.doSomething();
// config.noSuchMethod(); // does not compile
This is not ideal because you have to import the same module in your test twice - the real one just to get at the type of it and "proxiquired" one to actually use in your tests, and you have to be careful not to mix up the two. But it's pretty simple compared to the task of implementing another variant of module resolution for typescript. Also, when configType is used in this way - for typing only - its import will not even appear in generated javacsript code.

Resources