I am trying to export the result of a function in ES6. The function is unimportant - the following examples work for: const func = input => input
This works:
const a = 'foo'
const b = 'bar'
export default {
a: func(a),
b: func(b)
}
whereas these hit the error: SyntaxError: Unexpected token, expected ,:
export {
a: func(a),
b: func(b)
}
also:
export {
func(a) as a,
func(b) as b
}
Could you explain why? This does not seem to cover the above cases.
You can do
const aArg = 'foo'
const bArg = 'bar'
export const a = func(aArg);
export const b = func(bArg);
Named exports need a variable name to export, they can't export arbitrary expression results.
export default ...
You're exporting a single Object, Class, Function, etc.
export (Object, Class, Function) ...
You're exporting many Objects, Classes, Functions, etc. so you'll have to assign it to a name.
The first example is a little like if you teach at a school and have one student. You know who that student is and how to call him because he's the only one there. The second example, however, is like teaching a class with many students, you'll want some type of naming to call on the correct student(s).
Related
Is it possible to achieve same functionality as:
module.exports = {
a: 1,
b: 2
}
...which later allows:
import { a } from 'path/to/module'
by using ES6 modules like (or export default):
export const moduleName = {
a: 1,
b: 2
}
so that later rather than importing whole module into other one, only part of it will be imported
Use named exports instead:
export const a = 1;
export const b = 2;
Note that although this allows the consumer to do something like import { a } from ..., you're now not actually destructuring an object with an a property there, like you were doing originally with the module.exports syntax, you're just extracting the named export.
You can still export a default object in addition to using named exports, if you wanted:
export default { c: 'c', d: 'd' }
and then you can import with
import obj from '...';
const { c } = obj;
I'm trying to export an my module as an object but exporting it seems an 'anti pattern' (https://medium.com/#rauschma/note-that-default-exporting-objects-is-usually-an-anti-pattern-if-you-want-to-export-the-cf674423ac38)
So I was wondering what's the correct way to export an object and then use it as
import utils from "./utils"
`
utils.foo()
Currently I'm doing like so
/** a.js **/
function foo(){
//...
}
export {
foo
}
/** b.js **/
import * as utils from "a";
utils.foo()
is it correct like so? Do I maintain the tree-shaking feature?
thanks
If the object you want to import/export only contains some functions (as I assume due to the Utils name), you can export the functions separately as follows:
export function doStuff1() {}
export function doStuff2() {}
And import like this:
import {doStuff1, doStuff2} from "./myModule";
However, if the object you want to export holds state in addition to methods, you should stick to a simple export default myObject. Otherwise, calling the imported methods won't work as intended, since the context of the object is lost.
As an example, the following object should be exported as a whole, since the properties of the object should stay encapsulated. Only importing and calling the increment function would not mutate myObject since the context of the object cannot be provided (since it's not imported as a whole).
const myObject = {
counter: 0,
increment: function() {
this.counter++;
}
}
export default myObject;
es6 native way to do this:
// file1.es6
export const myFunc = (param) => {
doStuff(param)
}
export const otherFunc = ({ param = {} }) => {
doSomething({ ...param })
}
// file2.es6
import { otherFunc } from './file1.es6'
import * as MyLib from './file1.es6'
MyLib.myfunc(0)
MyLib.otherFunc({ who: 'Repley' })
otherFunc({ var1: { a1: 1 } })
And so on.
Can I destructure a default export object on import?
Given the following export syntax (export default)
const foo = ...
function bar() { ... }
export default { foo, bar };
is the following import syntax valid JS?
import { foo, bar } from './export-file';
I ask because it DOES work on my system, but I've been told it should NOT work according to the spec.
Can I destructure a default export object on import?
No. You can only destructure an object after importing it into a variable.
Notice that imports/exports have syntax and semantics that are completely different from those of object literals / object patterns. The only common thing is that both use curly braces, and their shorthand representations (with only identifier names and commas) are indistinguishable.
Is the following import syntax valid JS?
import { foo, bar } from './export-file';
Yes. It does import two named exports from the module. It's a shorthand notation for
import { foo as foo, bar as bar } from './export-file';
which means "declare a binding foo and let it reference the variable that was exported under the name foo from export-file, and declare a binding bar and let it reference the variable that was exported under the name bar from export-file".
Given the following export syntax (export default)
export default { foo, bar };
does the above import work with this?
No. What it does is to declare an invisible variable, initialise it with the object { foo: foo, bar: bar }, and export it under the name default.
When this module is imported as export-file, the name default will not be used and the names foo and bar will not be found which leads to a SyntaxError.
To fix this, you either need to import the default-exported object:
import { default as obj } from './export-file';
const {foo: foo, bar: bar} = obj;
// or abbreviated:
import obj from './export-file';
const {foo, bar} = obj;
Or you keep your import syntax and instead use named exports:
export { foo as foo, bar as bar };
// or abbreviated:
export { foo, bar };
// or right in the respective declarations:
export const foo = …;
export function bar() { ... }
Can I destructure a default export object on import?
Yes, with Dynamic Imports
To add to Bergi's answer which addresses static imports, note that in the case of dynamic imports, since the returned module is an object, you can use destructuring assignment to import it:
(async function () {
const { default: { foo, bar } } = await import('./export-file.js');
console.log(foo, bar);
})();
Why this works
import operates much differently in different contexts. When used at the beginning of a module, in the format import ... from ... , it is a static import, which has the limitations discussed in Bergi's answer.
When used inside a program in the format import(...), it is considered a dynamic import. The dynamic import operates very much like a function that resolves to an object (as a combination of named exports and the default export, which is assigned to the default property), and can be destructured as such.
In the case of the questioner's example, await import('./export-file.js') will resolve to:
{
default: {
foo: ...,
bar: function bar() {...}
}
}
From here, you can just use nested destructuring to directly assign foo, and bar:
const { default: { foo, bar } } = await import('./export-file.js');
I have a file that default exports an object containing constants. I'd also like to export each of the properties of the object. Is there a way to do this that doesn't involve writing them all out?
import keyMirror from 'keymirror';
// keymirror outputs an object with key = val. eg. {a: a, b: b, ...}
const types = keyMirror({
FREEFORM: null,
GRAPH_IMAGE: null,
...
});
export default types;
export const FREEFORM = types.FREEFORM;
export const GRAPH_IMAGE = types.GRAPH_IMAGE;
...
Not sure about export, though you can use a single destructuring assignment
const {FREEFORM, GRAPH_IMAGE, ..} = types;
Legacy lib.js:
function Foo () {...}
Foo.a = function() {...}
module.exports = Foo
Typing lib.d.ts:
declare module "foo" {
type Type = "a"|"b"|"c"
interface Foo {
(a: Type): string
...
}
export = Foo
// how do i export Type??
}
Consumer app.ts:
import Foo = require('foo')
// how do i get Type from lib.d.ts??
how do i get Type from lib.d.ts?
If is not exported you cannot get it.
This is a really old question, but I needed to answer it myself. If in this case "Foo" is the default modules.exports, then you can use export default on Foo in the module declaration:
declare module "foo" {
export type Type = "a"|"b"|"c" // export any custom types you like
export default interface Foo { // default works
(a: Type): string
...
}
}
Then elsewhere you can do:
import Foo, { Type } from 'foo'