I have a very small node Typescript project with the following structure:
When attempting to import the "diff" module in my index.ts file like so:
import * as diff from 'diff';
Atom-typescript suddenly loses the ability to locate my "fgtApp.Interfaces" namespace:
As soon as I remove the import statement, node is able to resolve the "fgtApp.Interfaces" namespace no issue like so:
Is this a bug in atom-typescript or a bug in my understanding of the way importing these external modules work?
Note: In very old versions of TypeScript namespaces were called ‘Internal Modules’, these pre-date JavaScript module systems. Modules can contain both code and declarations.
Without configuring the TypeScript compiler as discussed earlier, TypeScript will adopt the Node.js run-time resolution strategy by default in order to locate the requested modules at compile-time. To accomplish this, the TypeScript compiler will look for .ts files, .d.ts, .tsx, and package.json files.
Thus, for new projects modules would be the recommended code organization mechanism. Namespaces are a TypeScript-specific way to organize code. Namespaces are simply named JavaScript objects in the global namespace.
Use import * as chalk from "chalk";. A TypeScript module can say export default myFunction to export just one thing. Use import myFunction from "./myModule" to bring it in. More commonly, TypeScript modules say export myFunction in which case myFunction will be one of the properties on the exported object.
This isn't specifically a problem with atom-typescript. The atom-typescript plugin uses the official TypeScript language service (Same as Visual Studio), so this would be a problem in any editor.
The trouble is that once you have an import or export specified, the file becomes a module ("external module" pre-TypeScript 1.5). This means that when the import * as diff from 'diff';
is present, things declared in index.ts
become local only and don't consider/merge into the global namespace.
TypeScript spec, section 11.1: ...source files that contain at least one external import declaration, export assignment, or top-level exported declaration are considered separate external modules. Entities declared in an external module are in scope only in that module, but exported entities can be imported into other modules using import declarations
When you're not using external modules, TypeScript allows namespaces in different files to build upon each other. Once you start using external modules, this is no longer the case without using workarounds. In this case, it's often best to just switch to using external modules - if you're making a Node project, this is particularly easy because you don't have to worry about bundling.
Instead of a "deep namespace" (e.g. fgtApp.category.thing) like C# and .NET encourage - start thinking about each TypeScript source file as its own module. If you really do want a hierarchy, implement one with a folder structure.
This code will work as you expect even with noImplicitAny
active:
interfaces.d.ts
// Notice that this is a d.ts file. Since it will only contain interfaces,
// making it a d.ts file means TypeScript doesn't have to worry about
// emitting it and you also can't accidentally put executable code here.
export interface IFgtService {
authenticateDisable: boolean;
failedAttempt: boolean;
authenticate: (username: string, password: string) => boolean;
}
export interface IAnotherInterfaceAsAnExample {
isCool: boolean;
}
service.ts
// since there is no "relative path", diff will come from node_modules.
import * as diff from 'diff';
// since there IS a relative path, interfaces will come from ./interfaces.d.ts
import * as interfaces from './interfaces';
// You can still use namespaces inside an "external module", but mainly they
// serve as a convenient way to bundle stuff for a one-line export (see
// the last line of this file).
namespace Service {
export class FgtService implements interfaces.IFgtService {
authenticateDisable = true;
failedAttempt = true;
authenticate = (username: string, password: string) => {
let d = diff.d;
return true;
}
}
}
export = Service;
index.ts
import {FgtService} from './Service';
const myService = new FgtService();
console.log(myService.authenticateDisable);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With