TypeScript ES6 namespaces - node.js

I have a Node.js project I recently converted to TypeScript from ECMAScript 6-compatible JavaScript. I am still not entirely familiar with how TypeScript and ES6 interact, especially in regards to namespaces and types.
I have a subfolder in my project called sql which, as it sounds, exports a number of functions to interact with the project's MySQL database. I would like to organize my DB model types in a Sql.Models namespace, so they can be referenced e.g. Sql.Models.User. I would like my models to be declared in one or more .d.ts files inside the sql folder, but I can't figure out how to properly organize this so that these types can be referenced elsewhere. I obviously cannot require or import a .d.ts file; that's not a valid TypeScript operation. How can I use the type Sql.Models.User declared in a .d.ts file in another ES6-compatible TypeScript module?

How can I use the type Sql.Models.User declared in a .d.ts file in another ES6-compatible TypeScript module?
The following very simple setup works.
root
sql
models.d.ts
index.ts
tsconfig.json
The model.d.ts file declares a namespace and a type. As the image demonstrates, the index.ts file can alias that namespace and/or access it directly.
The above is using TypeScript version 2.2.1.

I solved this in a less-than-pretty fashion by using "aliased internal imports" which sound strange but really aren't. I export an alias to an internal symbol, which just happens to be a symbol imported from another file.
I would have preferred something like how C# works, where I can define the namespace in two files and somehow alias one from another so that only one file needs to be referenced, but this doesn't seem possible with ECMAScript 6-compatible TypeScript.

Related

Change default implementations of globals and folders for require and import functions in nodejs library

Is there a way I can change the default keys of nodejs like require? It seems they are immutable like require. I am aware I can reimplement require.resolve but I have to use require.resolve("./filepath") instead of require("./filepath")
Where are the key implementation files of globals like import, require actually stored in the installation folder? Are they .js files or native files? Any way to override the implementations directly or using Module loaders?

How to export types in a TypeScript npm module

In TypeScript, say I want to have the user use my module's "internal" types so they can properly type their own variables when using my module - do I just export literally everything from my index.ts file to accomplish this?
// index.ts
export * from './file1' // uses types/interfaces defined in file1types
export * from './file2' // uses types/interfaces defined in file2types
export * from './types/file1types'
export * from './types/file2types'
Do .d.ts files help me accomplish this, or are they only for non-TS projects? Does tsconfig.json's option declaration: true help me accomplish this by generating a .d.ts for every TS file? Is this an alternative to exporting everything from a single index.ts file?
And if declaration: true does help me accomplish this, how would the user use all those generated .d.ts files within the build folder?
I would greatly appreciate some clarification as to how one typically exports types in TS projects. Thanks in advance.
For those who are like me, and have made sure declaration: true is set in your tsconfig.json, and that your build process correctly creates the corresponding .d.ts files to the appropriate directory pointed to by your package.json file, AND STILL somehow can't access the internal types of your module when testing on an external project -- try restarting the TS server in VSCode (assuming you're using VSCode)
So much time was wasted trying to figure this out, only to realize Typescript was functioning fine and I was being sabotaged by my IDE.
Without declaration files you can develop a package in TypeScript, compile it and expose it to other users as JavaScript code. Including them also allows TypeScript developers to use the package with any types you defined in it. They can get more type information whilst working with your library, such as required arguments types, function return types etc, as well as warnings from their IDE/Intellisense when there are conflicts.
The declaration: true in the file tsconfig.json instructs the TypeScript compiler to output declaration files (.d.ts). Often they are bundled in a single file e.g. index.d.ts and then a "types": path/to/index.d.ts field is added to the library's package.json file to inform TypeScript where to look for the types (when a user imports the package).

VS Code Intellisense for auto exported global variables

Sails exports a set og global variables, such as:
_ (lodash)
sails (framework related)
ModelOne, ModelTwo, ModelThree, ... (the sails models we define)
Creating a jsconfig.json targeting es5 doesn't help since the variables aren't explicitly declared.
I have this variables declared on eslintrc.globals, but that just tells the linter they exist.
Ideally I'd like to have intellisense for this variables across my project.
Is there any way I can declare this global variable types in VS Code?
At the time of this writing, looking at the npm page for sails.js, they don't provide type declaration files, and don't have community contributed type declaration files in the Definitely Typed project.
Your options are:
Contribute type declaration files to the Definitely Typed project for sails.js (see their contributing instructions), and then install your contributed types package (like npm install -D '#types/sailjs' (or whatever it gets called))
Create your own type declarations NPM package (outside of the Definitely Typed project) and use that. In that case, see the TypeScript guide on publishing declaration files.
Create a type declaration file (myfDeclarationFile.d.ts or something of your choice) and define those types there. Put the file anywhere where it will be picked up as part of your project based on your tsconfig.json/jsoconfig.json file.
Note that in this case, you might need to make sure the name of the .d.ts file you create might need to not have the same name as other .ts files in the same directory (see https://github.com/microsoft/TypeScript/issues/51128).
In your particular case, since these are type declarations for globals, see TypeScript's guide for declaring types for global libraries. For guides for other types of libraries, see the guide index page.

Mixing typescript definition files with nodejs require over multiple files in an internal module

Are there any known issues with mixing nodejs modules (require) with typescript definition files (d.ts) multiple times over files within a module?
My scenario is that I have a module namespace per folder (much like I would in C#), then I basically compile them all via tsc to an outputted my-module.js. However I keep getting really odd errors like Could not find type HTMLElement but lots of people have pointed out that tsc includes the typescript lib file by default which contains all those types.
I have noticed a few people having odd errors when they are including the same d.ts files over multiple files which are all compiled with the --out flag to get it all into one file, so could this be causing my issues?
An example of my usage would be:
///<reference path="path/to/knockout.d.ts" />
import ko = require("knockout");
This would then be put in each file which requires knockout js, which is at least 10 files in the module i'm trying to compile currently. It just bombs out constantly saying knockout.d.ts cannot find the type HTMLElemet, Element, Document etc.
If you are using external modules (which you are if you have a top level "import" - as shown above), then you can't use the --out switch to combine multiple source files. It is a limitation that with external modules that one source file = one module. With source that is not in an external module (i.e. contributes to the 'global' scope), you can combine input source to one output JavaScript file using --out.
I have no idea about the "could not find HTMLElement" issues. If you can provide a repro (and outline which version you are using) I can take a look.

How to create a TypeScript Nodejs module spanning multiple files

I'm trying to create a Node.js module with a single namespace using TypeScript. I need the classes of the module to be in separate files, and have references to each other. I also need this module to utilize other node modules. But if I understand right, TypeScript only supports namespaces if a namespace is contained within a single file or the namespace does not use external modules.
Some people present the use of post-build tools to make the final module work, which is nice but doesn't address all the errors TypeScript throws when combining cross-file namespaces and imports during development.
Is it true that the closest solution is to create a module per file, and create a web of inter-imports?
I find that what works best for me for module dependencies is to always use source references, e.g.:
/// <reference path="other.ts" />
Since you can't generate single-file output from tsc if you use language-level imports/modules, I have resorted to using require as a function and so on.
This seems to be the same solution chosen by the TypeScript developers themselves (search for "require(" there). As suggested by silentorb's comment, you can declare the require function as some variation of the following (or use DefinitelyTyped):
declare function require(name: string): any;
Note that there's often a lot of discussion on the whole modularity topic in TS over on the TS forums (one recent example).

Resources