sinon.spy takes 2 parameters, object and function name.
I have a module as listed below:
module.exports = function xyz() { }
How do I define a spy for xyz? I don't have object name to use.
Thoughts?
The above actually doesn't work if you're using the ES6 modules import functionality, If you are I've discovered you can actually spy on the defaults like so.
// your file
export default function () {console.log('something here');}
// your test
import * as someFunction from './someFunction';
spyOn(someFunction, 'default')
As stated in http://2ality.com/2014/09/es6-modules-final.html
The default export is actually just a named export with the special name default
So the import * as someFunction gives you access to the whole module.exports object allowing you to spy on the default.
Related
I have referred all the questions in stackoverflow.
But none of the suggested why and when to use default export.
I just saw that default can be metioned "When there is only one export in a file"
Any other reason for using default export in es6 modules?
Some differences that might make you choose one over the other:
Named Exports
Can export multiple values
MUST use the exported name when importing
Default Exports
Export a single value
Can use any name when importing
This article does a nice job of explaining when it would be a good idea to use one over the other.
It's somewhat a matter of opinion, but there are some objective aspects to it:
You can have only one default export in a module, whereas you can have as many named exports as you like.
If you provide a default export, the programmer using it has to come up with a name for it. This can lead to inconsistency in a codebase, where Mary does
import example from "./example";
...but Joe does
import ex from "./example";
In contrast, with a named export, the programmer doesn't have to think about what to call it unless there's a conflict with another identifier in their module.¹ It's just
import { example } from "./example";
With a named export, the person importing it has to specify the name of what they're importing. They get a nice early error if they try to import something that doesn't exist.
If you consistently only use named exports, programmers importing from modules in the project don't have to think about whether what they want is the default or a named export.
¹ If there is a conflict (for instance, you want example from two different modules), you can use as to rename:
import { example as widgetExample } from "./widget/example";
import { example as gadgetExample } from "./gadget/example";
You should almost always favour named exports, default exports have many downsides
Problems with default exports:
Difficult to refactor or ensure consistency since they can be named anything in the codebase other than what its actually called
Difficult to analyze by automated tools or provide code intellisense and autocompletion
They break tree shaking as instead of importing the single function you want to use you're forcing webpack to import the entire file with whatever other dead code it has leading to bigger bundle sizes
You can't export more than a single export per file
You lose faster/direct access to imports
checkout these articles for a more detailed explanation:
https://blog.neufund.org/why-we-have-banned-default-exports-and-you-should-do-the-same-d51fdc2cf2ad
https://humanwhocodes.com/blog/2019/01/stop-using-default-exports-javascript-module/
https://rajeshnaroth.medium.com/avoid-es6-default-exports-a24142978a7a
With named exports, one can have multiple named exports per file. Then import the specific exports they want surrounded in braces. The name of imported module has to be the same as the name of the exported module.
// imports
// ex. importing a single named export
import { MyComponent } from "./MyComponent";
// ex. importing multiple named exports
import { MyComponent, MyComponent2 } from "./MyComponent";
// ex. giving a named import a different name by using "as":
import { MyComponent2 as MyNewComponent } from "./MyComponent";
// exports from ./MyComponent.js file
export const MyComponent = () => {}
export const MyComponent2 = () => {}
You can also alias named imports, assign a new name to a named export as you import it, allowing you to resolve naming collisions, or give the export a more informative name.
import MyComponent as MainComponent from "./MyComponent";
You can also Import all the named exports onto an object:
import * as MainComponents from "./MyComponent";
// use MainComponents.MyComponent and MainComponents.MyComponent2 here
One can have only one default export per file. When we import we have to specify a name and import like:
// import
import MyDefaultComponent from "./MyDefaultExport";
// export
const MyComponent = () => {}
export default MyComponent;
The naming of import is completely independent in default export and we can use any name we like.
From MDN:
Named exports are useful to export several values. During the import, one will be able to use the same name to refer to the corresponding value.
Concerning the default export, there is only a single default export per module. A default export can be a function, a class, an object or anything else. This value is to be considered as the “main” exported value since it will be the simplest to import.
There aren't any definitive rules, but there are some conventions that people use to make it easier to structure or share code.
When there is only one export in the entire file, there is no reason to make it named.
Also, when your module has one main purpose, it could make sense to make that your default export. In those cases you can extra named exports
In react for example, React is the default export, since that is often the only part that you need. You don't always Component, so that's a named export that you can import when needed.
import React, {Component} from 'react';
In the other cases where one module has multiple equal (or mostly equal) exports, it's better to use named exports
import { blue, red, green } from 'colors';
1st Method:-
export foo; //so that this can be used in other file
import {foo} from 'abc'; //importing data/fun from module
2nd Method:-
export default foo; //used in one file
import foo from 'blah'; //importing data/fun from module
3rd Method:-
export = foo;
import * as foo from 'blah';
The above methods roughly compile to the following syntax below:-
//all export methods
exports.foo = foo; //1st method
exports['default'] = foo; //2nd method
module.exports = foo; //3rd method
//all import methods
var foo = require('abc').foo; //1st method
var foo = require('abc')['default']; //2nd method
var foo = require('abc'); //3rd method
For more information, visit to Default keyword explaination
Note:- There can be only one export default in one file.
So whenever we are exporting only 1 function, then it's better to use default keyword while exporting
EASIEST DEFINITION TO CLEAR CONFUSIONS
Let us understand the export methods, first, so that we can analyze ourselves when to use what, or why do we do what we do.
Named exports: One or more exports per module. When there are more than one exports in a module, each named export must be restructured while importing. Since there could be either export in the same module and the compiler will not know which one is required unless we mention it.
//Named export , exporting:
export const xyz = () =>{
}
// while importing this
import {xyx} from 'path'
or
const {xyz} = require(path)
The braces are just restructuring the export object.
On the other hand , default exports are only one export per module , so they are pretty plain.
//exporting default
const xyz =() >{
};
export default xyz
//Importing
import xyz from 'path'
or
const xyz = require(path)
I hope this was pretty simple to understand, and by now you can understand why you import React modules within braces...
Named Export: (export)
With named exports, one can have multiple named exports per file. Then import the specific exports they want surrounded in braces. The name of imported module has to be the same as the name of the exported module.
// imports
// ex. importing a single named export
import { MyComponent } from "./MyComponent";
// ex. importing multiple named exports
import { MyComponent, MyComponent2 } from "./MyComponent";
// ex. giving a named import a different name by using "as":
import { MyComponent2 as MyNewComponent } from "./MyComponent";
// exports from ./MyComponent.js file
export const MyComponent = () => {}
export const MyComponent2 = () => {}
Import all the named exports onto an object:
// use MainComponents.MyComponent and MainComponents.MyComponent2 here
import * as MainComponents from "./MyComponent";
Default Export: (export default)
One can have only one default export per file. When we import we have to specify a name and import like:
// import
import MyDefaultComponent from "./MyDefaultExport";
// export
const MyComponent = () => {}
export default MyComponent;
Note: The naming of import is completely independent in default export and we can use any name we like.
Here's a great answer that explains default and named imports in ES6
The following is a section from MDN's reference on the JavaScript import statement (with added emphasis):
Import a single export from a module
Given an object or value named myExport which has been exported from the module my-module either implicitly (because the entire module is exported) or explicitly (using the export statement), this inserts myExport into the current scope.
import {myExport} from '/modules/my-module.js';
I know what it means for an object or value to have been exported from a module explicitly (using the export statement), but how can they be exported implicitly (impliedly without using an export statement)? What does it mean for an "entire module" to be exported?
I think the wording on this statement is somewhat confusing, assuming I understand it correctly. I think what they mean by "explicitly" would be explicitly named, e.g.
export { foo };
// or others
export var foo;
export function foo(){}
export class foo {}
export { foo } from "./foo.js";
whereas implicitly would be one that is not explicitly named, like
export * from "./foo.js";
where then doing
import { foo } from "./mod.js";
would work as long as mod is re-exporting foo from the foo.js file.
lets make it this way
Given an object or value named myExport which has been exported implicitly (because the entire module is exported) from a module
or
Given an object or value named myExport which has been exported explicitly (using the export statement) from a module
so i can export an object or func like this
// ./modules/my-module.js
export default UserApi = {
myExport: function() {
console.log(please make api call)
}
}
// ./otherfile.js
import {myExport} from '/modules/my-module.js';
i never explicitly export myExport but you can import myExport without importing UserApi which i explicitly export
Shouldn't
import * as convict from "convict";
const config = convict({ ... });
// Perform validation
config.validate({ "allowed": "strict" });
export = config;
be functionally equivalent to:
import * as convict from "convict";
export const config = convict({ ... });
// Perform validation
config.validate({ "allowed": "strict" });
The first snippet works, but the second snippet introduces type errors such as:
TypeError: config.get is not a function
When imported using:
import * as config from "./config";
(This question and Frequent issue with TypeScript and preferring import over require are different. This question is about exports and what should be two equivalent usages. The other question is about imports.)
export const config = ... is so called "named export", it adds config variable to the list of names exported by the module. You can look at various variants of es6 export statement here, this particular one corresponds to the 4th line of the first example (note 'also var, const' comment):
export let name1 = …, name2 = …, …, nameN; // also var, const
and can be used with "named import* like
import {config} from '...';
export = config is entirely different, it's typescript-only export assignment. The documentation says that is should be imported as import config = require(...) which is again typescript-only special syntax.
With current version of TypeScript, export assignment can also be imported as
import * as config from 'module';
but there is breaking change in the works, in the future (maybe as soon as 2.8) this import will stop working with export assingment and will have to be written as
import config from 'module';
The two are indeed different. Essentially, it all has to do with the fact that in the second case config is a named export.
The first snippet produces an export that is just the config. If you did require("./config"), you'd get that config object. This is because you set the exports object to the config. That's why you have to do * as config when importing, because the entire imported object is what you're looking to get.
The second snippet produces an object with a named config field that points to your config; this is equivalent (ish) to doing:
exports = {
config: convict({ ... })
};
In this example, config is a named export. To import it, you'd have to get the config field of the exported object:
import { config } from "./config";
I am really confused about:
export const foo
export default foo
module.exports = foo;
I know these are very basic but could someone please differentiate and explain these to me. I really want to understand.
Let take each of these one by one.
export const
export const foo
This is ES6 export syntax for a named export. You can have many named exports. It says that you want to export the value of the variable foo and you are also declaring that symbol to be const in this module.
You can't actually use export const foo all by itself just like you can use const foo; all by itself. Instead, you would have to assign something to it:
export const foo = 12;
The const applies only to within the module itself. It does not affect what someone can do with the value once they've imported the value from the module on the other end because at the other end (where its imported), it's value is copied into another variable. If that other variable is created with the import statement, then it is automatically const on the import side (you cannot assign to it) no matter what it was declared on the export side.
This could be imported as either of these:
import {foo as localFoo} from 'lib';
import {foo} from 'lib';
The first imports the foo property of the module into a localFoo named variable.
The second imports the foo property of the module into a foo named variable.
export default
export default foo
This is also ES6 syntax and says that you also want to export the value of the variable foo and you want that to be the default export value so if someone imports just the module and not any properties of the module, this is the variable they will get. You can only have one default export per module.
Internally, the default export is really just a named export with the special name default assigned:
import localVar from 'myLib';
This will get the default export from myLib and assign it's value to a locally declared variable named localVar. The above is a shorthand for this:
import { default as localVar } from 'lib';
So, the default export just allows you to have a shortcut import for one particular export. The ES6 import/export syntax was designed to make the syntax as brief as possible for the default import/export. But, for obvious reasons, there is only one default property per module.
module.exports
// inside of myModule
module.exports = foo;
This is node.js syntax for exporting the value of the variable foo and you're exporting it at the top level. When someone uses this module:
let x = require('myModule');
console.log(x); // will show the value of `foo` from the previous module
This is not ES6 syntax, but is regular ES5-compatible syntax using the module.exports and require() infrastructure built into node.js.
The export statement is used to export functions, objects or primitives from a given file (or module).
Named Exports
This is a named export in ES6 javascript
export const foo
which is imported like:
import { foo } from 'path'
Default Export
This is a default export (This can be imported using any name)
export default foo
which is imported like so:
import bar from 'path'
This is commonjs export which is used in nodejs programs.
module.exports = foo;
which is imported like:
var foo = require('path')
For more details
export const foo : exports constants (ES6)
export default foo : exports object (ES6)
Above statements are ECMA Script 2015 (aka ES6) implementation.
In an normal ES6 JS file one can export any object(variable) or constants. Pls note that you cannot change constant reference, though internal structure can be modified(weird).
In ES6 one can have multiple exports in module(script file). which can be added in calling script as
import {Obj1, Obj2} from module_file
coming to export default, One can have only one export default in module. and while importing when exact names are not defined default is been picked up.
module.exports = foo; is older implementation and it is same as export default. except it is imported with require statement instead of import
for more refer https://developer.mozilla.org/en/docs/web/javascript/reference/statements/export
I have an external library thing.d.ts file with a global definition inside:
declare var thing: ThingStatic;
export default thing;
I reference npm module in my TypeScript:
import thing from 'thing';
...
thing.functionOnThing();
When I transpile the TS (targeting ES6) it looks something like this:
const thing_1 = require("thing");
...
thing_1.default.functionOnThing();
This then throws an error:
Cannot read property 'functionOnThing' of undefined
Why is TypeScript adding .default between thing_1 and functionOnThing()?
There is no property named default on ThingStatic, and no default property on the underlying JS object that the .d.ts file defines.
Why is TypeScript adding the property and how do I stop it?
import thing from 'thing';
This line of code means "import the default export from the module 'thing' and bind it to the local name thing".
TypeScript does as you requested and accesses the default property of the module object.
What you probably meant to write was
import * as thing from 'thing';
This appears to be a bug with global TS definitions and "module": "commonjs" in the tsconfig.json.
You can either use global TS definitions and stitch all your output into a single file, or you can use modules and directly import them.
The error here is due to the require returning the module context, and the name of the default being irrelevant - it always becomes default...
declare var thing: ThingStatic;
export thing; // Explicit export for thing
export default thing; // Default export for thing
Now require will return this context, so with commonjs modules:
import module from 'thing';
var thing = module.default; // From the default export
var alsoThing = module.thing; // From the named export
However, I've found this to be inconsistent, so switched to es6 modules:
import thing from './thing'; // Import default
import { thing } from './thing'; // Import named
const thing = (await import('path/to/thing.js')).default; // Import dynamic