Loading typescript external module without importing? - node.js

I am having a headache at the moment because I am writing a nodejs typescript app which is basically one big internal module (spread over lots of files and outputted as one).
Now the problem I have is that express.d.ts (found on definitely typed) is written so it can only be loaded as an external module: import express = require("express"); however then that means that I have to compile my application as a single file as the moment you put the import keyword in it treats it like your module is now external, which I do not want.
So is there any way for me to change this code:
/// <reference path="../../../typescript-descriptors/express/express.d.ts" />
import express = require('express');
var app = express();
app.get('/', (req: express.Request, res: express.Response) => {
res.render('index');
});
so it does not require the import and I can just do var express = require("express"); and still get the type safety?
As I NEED to be able to split my TS logic over multiple files and using the import method does not allow this.

Updated based on the comment...
Express itself is what TypeScript calls an external module. It is not possible to import an external module into an internal module - so you can't actually achieve what you want directly here.
However, if the real underlying problem is...
As I NEED to be able to split my TS logic over multiple files and using the import method does not allow this
What is stopping you from simply switching to external modules, which allows you to split your logic into many files and import them as needed? Rather than trying to combine the output into a single file - lean on the simple module loading that Node gives you for free and you're back in the game!

Related

How to import module based dependencies for firebase cloud functions?

I want to organize my firebase cloud functions in specific files,
and currently, I have these 3:
index.ts
crypto.ts
webscrape.ts
Inside of these files, I have functions that use specific dependencies that are needed nowhere else.
For example, in crypto.ts I need the crypto-js package to encrypt some user data and store it into the database.
So I am importing it like so:
import * as CryptoJS from "crypto-js";
as advised in https://firebase.google.com/docs/functions/handle-dependencies#typescript
On the other hand, when I try to import puppeteer into webscrape.ts like this:
import * as puppeteer from"puppeteer-extra";
then calling puppeteer.launch(); gives me an error :
Property 'launch' does not exist on type 'typeof import("c:/Users/username/Desktop/project/firebasee/functions/node_modules/puppeteer-extra/dist/index")'
and it only works when I do const puppeteer = require("puppeteer-extra");
What's the difference here?
My goal is to keep the dependencies of each functions and file/module as small as possible because I assume that this will also keep the size of each function container small (Is that even true?)
I didn't want to import everything to index.ts even when I trigger a function, that doesn't use this dependency at all.
So what is the correct way of handling these dependencies?
Thanks!
The following import will get the default export from that package.
import puppeteer from "puppeteer-extra"
I looked for the default export in the Github repository and found that.
const defaultExport: PuppeteerExtra = (() => {
return new PuppeteerExtra(...requireVanillaPuppeteer())
})()
export default defaultExport
They have mentioned both ES6 import and require methods here.
// javascript import
const puppeteer = require('puppeteer-extra')
// typescript/es6 module import
import puppeteer from 'puppeteer-extra'
You can read more about import on MDN.

How can I avoid always having to import my own code in Typescript?

So I was recently hacking on a large Typescript project (https://github.com/BabylonJS/Babylon.js) and I noticed that they don't ever have to import anything, they just use their namespace and the rest is (seemingly) magic.
It got me thinking that I would like to use something similar for myself, so I started a simple typescript project to try it out.
tsconfig.json
{
"compilerOptions": {
"baseUrl": "src",
"outFile": "server.js"
}
}
src/main.ts
module Test {
console.log('Main started')
const server:Server = new Server()
}
src/Server.ts
// import * as http from 'http'
module Test {
export class Server {
constructor() {
console.log('Server initialized')
}
}
}
If I build this Typescript project then I get output like the following:
// import * as http from 'http'
var Test;
(function (Test) {
var Server = /** #class */ (function () {
function Server() {
console.log('Server initialized');
}
return Server;
}());
Test.Server = Server;
})(Test || (Test = {}));
var Test;
(function (Test) {
console.log('Main started');
var server = new Test.Server();
})(Test || (Test = {}));
So far, so good. The trouble is that I want to take advantage of some external modules, in this case namely the http module, so I uncomment the import line above and now Typescript reports:
src/server/Server.ts(1,1): error TS6131: Cannot compile modules using option 'outFile' unless the '--module' flag is 'amd' or 'system'.
Node uses the commonjs module system, so obviously setting either of those flags isn't going to help me much. I have none the less tried them as well as various other combinations of flags, but to no avail. I noticed that BabylonJS doesn't really use external imports like that, opting instead to declare them as external and provide them globally at execution time as script tags. Is there maybe an analogue to that for Node?
You can't have these two things at the same time, namely
How can I avoid always having to import my own code in Typescript?
and
I want to take advantage of some external modules
You can avoid imports only by not using external modules, and the result will be one giant script file that can use external dependencies only as globals created by scripts loaded via script tag, as you already noticed.
The language does not allow you to use external modules when you do this. If you have an import of external module at the top level, your file becomes a module and there is no way it could use code from your other files without importing them. And having import of external module inside a namespace is not allowed AFAIK.
That said, I don't think your question - "How can I avoid always having to import my own code in Typescript?" - has a valid premise. CommonJS module system is the solution for preventing large projects from becoming unmaintainable mess. It does not matter if some part of a project is your own code or some external dependency - if it's a separate part with well-defined interface, it should be packaged and consumed as a module.
The solution that worked for me is this:
Server.ts
declare var http: any;
namespace Test {
export class Server {
constructor() {
console.log('Server initialized')
const server = http.createServer()
server.listen()
}
}
}
Then I simply provide http at runtime, for example by prepending a var http = require('http') to the output. Thanks to artem for a nudge in the right direction.

How to use multiple compiled ts files in a node module?

Currently I am trying to use TypeScript to create JavaScript-Files which are then required in a index.js file. I am using VS 2015 Update 3 with node.js tools 1.2 RC. Sadly it is not working like I thought it would.
To begin with here is my initial idea:
I have a node module (to be precise, it is a deployd module http://docs.deployd.com/docs/using-modules/). This module is handling payment providers like paypal or stripe. Now I want to use TypeScript to write interfaces, classes and use types to make it easier to add new payment providers. The old .js files should still be there and used. I want to migrate step by step and use the self-written and compiled .js files together. So I thought I can create .ts files, write my code, save, let VS compile to js and require the compiled js file in another js file. Okay, that is my idea... Now the problem
I have a PaymentProvider.ts file which looks like this
import IPaymentProvider = require("./IPaymentProvider.ts"); // Interface, can't be realized in JavaScript, just TypeScript
export abstract class PaymentProvider implements IPaymentProvider.IPaymentProvider
{
providerName: string;
productInternalId: number;
constructor(providerName : string)
{
this.providerName = providerName;
}
//... some methods
};
The other file is PaypalPaymentProvider.ts
import PaymentProvider = require("./PaymentProvider.ts");
export class PaypalPaymentProvider extends PaymentProvider.PaymentProvider
{
constructor()
{
super("paypal");
}
// more methods
}
VS 2015 doesn't show any errors. The js and .js.map files are generated. Now I thought I could require the files and that's it. I tried to use the PaypalPaymentProvider.js like this const PaypalPaymentProvider = require("./lib/payment-provider/PaypalPaymentProvider.js"); (yes, it is located there) but it's not working. When starting the index.js via node I get the following error:
...\Path\PaymentProvider.ts:1 (function (exports, require, module, __filename, __dirname) { import IPaymentProvider = require("./IPaymentProvider.ts"); Unexpected token import....
I find it strange that this is the error, because JavaScript doesnt't have Interfaces. The compiled IPaymentProvider.js is empty.
Also I thought that TypeScript is mainly for development and the compiled JavaScript for production. So why it is requiring a ts-file? I thought imports in typescript will be converted to require of the compiled js-file?
Do I need to require all compiled js files and not only the one I currently try to use? (I don't think so...)
To be honest, I think the main problem is that I am new to TypeScript and make something wrong from the very beginning.
Any help/advice? Thanks!
I have the solution... Thanks to Paelo's links I was able to see that I need to omit the file ending! So the really simple solution was to write
import IPaymentProvider = require("./IPaymentProvider");
instead of
import IPaymentProvider = require("./IPaymentProvider.ts");
When I changed that in every ts file it worked perfectly!

What makes a typescript module, a typescript module? Toastr example

I was just using toastrjs for a few notifications, and I ran into this little problem. Ideally, when you import a library in nodejs, you have to make an import statement, like so:
import http = require("http");
However, when I tried this with toastr, I get an error, even after including the reference path. So, something like this:
///<reference path='toastr.d.ts' />
import toastr = require("./toastr");
I get this error:
error TS2071: Unable to resolve external module '"./toastr.js"'.
error TS2072: Module cannot be aliased to a non-module type.
How is toastr different from a regular node module like http?
Update 1
I tried to do the same thing with jQuery but I have the same problems, does this mean that this does not work with frameworks that are designed to be client-side?
the following declare definition would create a module you can import via amd/commonjs:
declare module "jquery"{
export var jQuery: JQueryStatic;
}
Then you can do:
import jquery = require("jquery");
You can see such definitions in this underscore definition: https://github.com/borisyankov/DefinitelyTyped/blob/master/underscore/underscore.d.ts#L2853
or node.d.ts : https://github.com/borisyankov/DefinitelyTyped/blob/master/node/node.d.ts#L203
However not all files on DT have this definition. As it is simple enough to add on your own and you are free to name these modules whatever you want (in your AMD configuration http://www.youtube.com/watch?v=4AGQpv0MKsA )

nodejs module does not export function

I ran into an issue with my Nodejs application.
I have two different apps that are using shared library, which is located so that it is found one level up in node_modules. So i have this structure ./app1/app.js, ./app2/app.js and ./node_modules/shared.libs/index.js.
shared.libs in its turn has some other modules installed, like mongoose, redis etc. Plus some mogoose models with additional functions in them. All are exported from index.js like this:
exports.async = require('async');
exports.config = require('./config');
exports.utils = require('./lib/utils');
And then in apps i import them like this:
var libs = require('shared.libs');
var config = libs.config;
So after this code i can use config which is coming from that shared library.
This part was and is working just fine. But now i need to put additional layer on top of this library (read: provide more unified interface for both apps).
What i tried to do is to add some functions into index.js of shared library and then export the whole object with these functions. But whenever i try to call previously imported (by var libs = require('shared.libs');) object it says that libs is not defined.
What am i doing wrong here?
I generally want to keep other code the same, so i won't need to go over replacing require part everywhere, but at the same time provide additional functionality from shared library which will be available from that imported libs object.
this should definitely work:
module.exports = {
async: require('async'),
config: require('./config'),
utils: require('./lib/utils'),
foo: function () {
return 'bar';
}
};
reference like:
var libs = require('shared.libs');
console.log(libs.async);
console.log(libs.config);
console.log(libs.utils);
console.log(libs.foo);
console.log(libs.foo());
What makes me wonder is one of your comments above, that you get an error libs is not defined. That looks like you should have other unnoticed errors before.. during the the initialization of your shared.libs module..

Resources