I have a library that is in a name space, somewhat like this:
namespace MyLib {
export class MyClass {}
}
I then have another class that is not in the namespace that looks like this:
class Test extends MyLib.MyClass {}
Is there a way for me to access MyClass without having to prefix the namespace? Maybe something like this:
import MyLib;
class Test extends MyClass {}
Edit
I found out that I can do this:
import MyClass = MyLib.MyClass;
Which is okay, but based on that is there anyway for me to import all classes in the namespaces?
The namespacing convention is a C#-ism that doesn't translate very well to JavaScript. My suggestion would be to stop using it altogether because it'll cause more headaches than solve actual problems.
Instead, you should treat your modules themselves as namespace "things". You could do this:
// MyLib.ts
class MyClassA {}
class MyClassB {}
export {
MyClassA,
MyClassB,
};
// Your code
import { MyClassA, MyClassB } from "./MyLib.ts";
Or in separate files:
// MyClassA.ts
export class MyClassA {}
// MyClassB.ts
export class MyClassB {}
// MyLib.ts
import MyClassA from "./MyClassA";
import MyClassB from "./MyClassB";
export {
MyClassA,
MyClassB,
};
// Your code
import { MyClassA, MyClassB } from "./MyLib.ts";
You can't "import all names" though, not in the way you'd need in C# where things are just magically scoped. They need to be declared somehow. On your example code, there's no way to tell that Test comes from MyLib - indeed, even though you could make it work (through global variables, e.g. window.Test = Test), TypeScript wouldn't be happy about it as it wouldn't be able to find a definition for Test, you'd need to declare var it somewhere.
Related
I have two different classes:
Class1.js
class Class1 {
initialize = () => {
console.log("Class1 Initializer");
}
}
export default Class1;
Class2.js
class Class2 {
initialize = () => {
console.log("Class2 Initializer");
}
}
export default Class2;
classes/index.js
import Class1 from "./Class1";
import Class2 from "./Class2";
export default {
Class1,
Class2
}
Then I'm trying to use the classes:
server.js
import { Class1, Class2 } from "./classes";
...
Class1.initialize() <<<<==== ERROR - Cannot read property `initialize` of undefined.
What is the correct syntax of the imports and exports? Why is that error happening?
My understanding is, your method of exporting is possible and that this problem is caused by initialize() being an instance method of Class1. You'll need to create an instance of Class1 before calling initialize(). One way to instantiate Class1 would be via new:
import { Class1, Class2 } from "./classes";
// Create "new" instance of Class1, and then call initialize() on it
(new Class1()).initialize()
Couple things here.
First, you're using arrow syntax in your class methods. Arrow functions don't bind to their own "this" the same way that normal functions do. I'd recommend refactoring that code to mirror below. Do the same for both Class1 and Class2.
class Class1 {
initialize() {
console.log("Class1 Initializer");
}
}
Two, if you're using the ES6 export syntax, you can only ever have one default. In your index.js file, you'll want to just to export { Class1, Class2}, but you can't use export default { Class1, Class2 }.
Three, you need to create an instance of the class before you can call its method. You can either create a new variable that initializes a new instance of the class, then call the method, or you can do it all in-line.
new Class2().initialize();
Fourth, you're importing from a file called a file called "./classes". As far as I can tell that doesn't exist. It should be from "./index".
Hope this helps!
You are using default on object literal. You cant do that.
Do below in classes/index.js:
import Class1 from "./Class1";
import Class2 from "./Class2";
export {
Class1,
Class2
}
and then use :
import * as Classes from "./classes";
Then :
new Classes .Class2().initialize();
By the way how are running above example? its like node server.js?? Node 8.5.0 + supports ES6 like import and export style and file extension also should be .mjs otherwise .js file will need to use require function
This may have been answered somehow already, but wasn't sure how to ask it.
I have a Typescript file that exports a single class:
export class MyClass {
...
}
I have a Javascript file that imports the transpiled version of that typescript and uses it:
define('random-source', ['src/my-class'], function(MyClassMod) {
...
var myClass = new MyClassMod.MyClass();
...
});
My question is this: Is there a way to write the Typescript file so that the only object exported is that 'MyClass' definition? As you see from the define in the Javascript, it's imported as a module name, but I have to say '.MyClass' to access it. When I have a lot of Typescript files with a single class defined like this, it makes the Javascript code a bit messy. Ideally I'd like something like:
define('random-source', ['src/my-class'], function(MyClass) {
...
var myClass = new MyClass();
...
});
Is that possible? Thanks in advance!
Actually you are looking for an export assignment, which will make MyClass the value of the entire module:
class MyClass {
// ...
}
export = MyClass;
Seems like you are looking for a default export:
export default class MyClass {
...
}
I am new to Aurelia, but am working on an existing project and learning as I go.
I want to add a javascript class file and have NPM include it in the build, but I cannot find clear documentation on how to do that.
It is not a complex class and does not require an html template.
Just add the .js file containing your class to your src folder and add the following to import it in the file you intend to use the class.
import * as MyClass from './my-classs';
following the convention, you can create a class with the below...
export class MyClass {
myProperty = 'foo';
myOtherProperty = { key:'value' };
constructor() {
// constructor stuff (optional of course)
}
myMethod() {
// do something
}
}
Then in your ViewModel, for example...
import { inject } from 'aurelia-framework';
import { MyClass } from 'path/to/my-class';
#inject(MyClass)
export class MyViewModel {
constructor(myClass){
this.myClass = myClass;
}
attached() {
console.log(this.myClass.myProperty);
this.myClass.myMethod();
}
}
The way you import your class does depend on whether it's written as a module or not. If it's not a module, you'll have to write it out as #john-little mentioned.
The MyClass will automatically be a singleton until you make it transient (see https://aurelia.io/docs/fundamentals/dependency-injection#object-lifetime-child-containers-and-default-behavior)
I've got a conundrum for you. I'm fairly new to Typescript, but I've enjoyed the experience thus far. Wanting to be a good developer and logically group my modules into namespaces I've come across a rare? issue. Here's the simplest example to recreate the problem.
Lets say you got a class... we'll call it ClassA, which references a class aptly named ClassB which resides in a child namespace.
namespace Foo {
export class ClassA {
public classB: Bar.ClassB;
public constructor() {
}
}
}
and
namespace Foo.Bar {
export class ClassB {
public constructor() {
}
}
}
Typescript couldn't be happier with this. Well when I want to import things for ClassA, I'll put it inside the namespace like so:
namespace Foo {
import SomeClass = SomewhereElse.SomeClass;
export class ClassA {
public classB: Bar.ClassB;
public constructor() {
}
}
}
Again... we cool. But what if I wanted to import an ambient module?
namespace Foo {
import * as SockJS from "sockjs-client"; // TS1147 GRUMBLE! CAN'T DO DAT HERE!
export class ClassA {
public classB: Bar.ClassB;
public constructor() {
}
}
}
Ok, that's fine. I'll just move it outside the namespace like it's telling me to.
import * as SockJS from "sockjs-client";
namespace Foo {
export class ClassA {
public classB: Bar.ClassB; // TS2503:Now you're just a Bar that I used to know
public constructor() {
}
}
}
Suddenly Typescript gets amnesia and doesn't know what Bar is. It doesn't recognize child namespaces. I've tried several ways to make it remember like nesting the namespaces or exporting them, but nothing will make it recognize this. What's the dilly yo? Any of you cool cats know what's going on or how I can resolve it and keep my child namespaces?
Suddenly Typescript gets amnesia and doesn't know what Bar is. It doesn't recognize child namespaces. I've tried several ways to make it remember like nesting the namespaces or exporting them, but nothing will make it recognize this. What's the dilly yo
Its because namespaces are global. And modules are modular. So as soon as you import a module into your file, your file becomes a module. https://basarat.gitbooks.io/typescript/content/docs/project/modules.html
Suggestion
Please use modules. There are plenty of reasons : https://github.com/TypeStrong/atom-typescript/blob/8d43dd1b930a6df0ce62454a1560acfb7eee24c9/docs/out.md
I am using TypeScript 1.6 with ES6 modules syntax.
My files are:
test.ts:
module App {
export class SomeClass {
getName(): string {
return 'name';
}
}
}
main.ts:
import App from './test';
var a = new App.SomeClass();
When I am trying to compile the main.ts file I get this error:
Error TS2306: File 'test.ts' is not a module.
How can I accomplish that?
Extended - to provide more details based on some comments
The error
Error TS2306: File 'test.ts' is not a module.
Comes from the fact described here http://exploringjs.com/es6/ch_modules.html
17. Modules
This chapter explains how the built-in modules work in ECMAScript 6.
17.1 Overview
In ECMAScript 6, modules are stored in files. There is exactly one
module per file and one file per module. You have two ways of
exporting things from a module. These two ways can be mixed, but it is
usually better to use them separately.
17.1.1 Multiple named exports
There can be multiple named exports:
//------ lib.js ------
export const sqrt = Math.sqrt;
export function square(x) {
return x * x;
}
export function diag(x, y) {
return sqrt(square(x) + square(y));
}
...
17.1.2 Single default export
There can be a single default export. For example, a function:
//------ myFunc.js ------
export default function () { ··· } // no semicolon!
Based on the above we need the export, as a part of the test.js file. Let's adjust the content of it like this:
// test.js - exporting es6
export module App {
export class SomeClass {
getName(): string {
return 'name';
}
}
export class OtherClass {
getName(): string {
return 'name';
}
}
}
And now we can import it in these three ways:
import * as app1 from "./test";
import app2 = require("./test");
import {App} from "./test";
And we can consume imported stuff like this:
var a1: app1.App.SomeClass = new app1.App.SomeClass();
var a2: app1.App.OtherClass = new app1.App.OtherClass();
var b1: app2.App.SomeClass = new app2.App.SomeClass();
var b2: app2.App.OtherClass = new app2.App.OtherClass();
var c1: App.SomeClass = new App.SomeClass();
var c2: App.OtherClass = new App.OtherClass();
and call the method to see it in action:
console.log(a1.getName())
console.log(a2.getName())
console.log(b1.getName())
console.log(b2.getName())
console.log(c1.getName())
console.log(c2.getName())
Original part is trying to help to reduce the amount of complexity in usage of the namespace
Original part:
I would really strongly suggest to check this Q & A:
How do I use namespaces with TypeScript external modules?
Let me cite the first sentence:
Do not use "namespaces" in external modules.
Don't do this.
Seriously. Stop.
...
In this case, we just do not need module inside of test.ts. This could be the content of it adjusted test.ts:
export class SomeClass
{
getName(): string
{
return 'name';
}
}
Read more here
Export =
In the previous example, when we consumed each validator, each module only exported one value. In cases like this, it's cumbersome to work with these symbols through their qualified name when a single identifier would do just as well.
The export = syntax specifies a single object that is exported from the module. This can be a class, interface, module, function, or enum. When imported, the exported symbol is consumed directly and is not qualified by any name.
we can later consume it like this:
import App = require('./test');
var sc: App.SomeClass = new App.SomeClass();
sc.getName();
Read more here:
Optional Module Loading and Other Advanced Loading Scenarios
In some cases, you may want to only load a module under some conditions. In TypeScript, we can use the pattern shown below to implement this and other advanced loading scenarios to directly invoke the module loaders without losing type safety.
The compiler detects whether each module is used in the emitted JavaScript. For modules that are only used as part of the type system, no require calls are emitted. This culling of unused references is a good performance optimization, and also allows for optional loading of those modules.
The core idea of the pattern is that the import id = require('...') statement gives us access to the types exposed by the external module. The module loader is invoked (through require) dynamically, as shown in the if blocks below. This leverages the reference-culling optimization so that the module is only loaded when needed. For this pattern to work, it's important that the symbol defined via import is only used in type positions (i.e. never in a position that would be emitted into the JavaScript).
Above answers are correct. But just in case...
Got same error in VS Code. Had to re-save/recompile file that was throwing error.
How can I accomplish that?
Your example declares a TypeScript < 1.5 internal module, which is now called a namespace. The old module App {} syntax is now equivalent to namespace App {}. As a result, the following works:
// test.ts
export namespace App {
export class SomeClass {
getName(): string {
return 'name';
}
}
}
// main.ts
import { App } from './test';
var a = new App.SomeClass();
That being said...
Try to avoid exporting namespaces and instead export modules (which were previously called external modules). If needs be you can use a namespace on import with the namespace import pattern like this:
// test.ts
export class SomeClass {
getName(): string {
return 'name';
}
}
// main.ts
import * as App from './test'; // namespace import pattern
var a = new App.SomeClass();
In addition to A. Tim's answer there are times when even that doesn't work, so you need to:
Rewrite the import string, using the intellisense. Sometimes this fixes the issue
Restart VS Code
I had this issue and I had forgotten to export the Class.
In addition to Tim's answer, this issue occurred for me when I was splitting up a refactoring a file, splitting it up into their own files.
VSCode, for some reason, indented parts of my [class] code, which caused this issue. This was hard to notice at first, but after I realised the code was indented, I formatted the code and the issue disappeared.
for example, everything after the first line of the Class definition was auto-indented during the paste.
export class MyClass extends Something<string> {
public blah: string = null;
constructor() { ... }
}
Just in case this may works for you as it did form me, i had this files
//server.ts
class Server{
...
}
exports.Server = Server
//app.ts
import {Server} from './server.ts'
And this actually raised an error but i changed server.ts to
//server.ts
export class Server{
...
}
and it worked 😎👌
Note: i am using this config
"target": "esnext",
"module": "commonjs",
I faced the same issue in a module that has no exports. I used it for side-effects only. This is what the TypeScript docs say about importing side-effects modules:
Though not recommended practice, some modules set up some global state that can be used by other modules. These modules may not have any exports, or the consumer is not interested in any of their exports. To import these modules, use:
import "./my-module.js";
In that situation, you can fix the "File is not a module" error by simply exporting an empty object:
// side-effects stuff
export default {};
I faced the same issue ("File is not a module error") for import js in vue component
import handleClientLoad from "../../../public/js/calendar.js"
I do this and solve it
// #ts-ignore
import handleClientLoad from "../../../public/js/calendar.js"
The file needs to add Component from core hence add the following import to the top
import { Component } from '#angular/core';