10

I can easily have an export default with multiple values:

class Car {...}
class Bus {...}

export default { Car, Bus }

I can also easily have an export default of a type

export default interface Airplane {...}

But I can't have a default export of multiple types

interface Airplane {...}
interface Motorcycle {...}

// 'Airplane' only refers to a type, but is being used as a value here. ts(2693)
export default { Airplane, Motorcycle }

Or of a mix of multiple types and values.

class Car {...}
interface Motorcycle {...}

// 'Airplane' only refers to a type, but is being used as a value here. ts(2693)
export default { Car, Airplane }

How can I achieve this?

6
  • You can't mix types and values in a default export object. Why do you want to do this? Default exports objects in general are considered by some (including myself) as harmful. Just export each thing individually. Commented Mar 25, 2019 at 13:21
  • There is a prefer-default-export linting rule. Airbnb would disagree with you it seems: github.com/airbnb/javascript/issues/1365 Commented Mar 25, 2019 at 13:46
  • Yes, some (including myself) disagree with Airbnb on this. Also to note, exporting a bunch of stuff on an object breaks the spirit of Airbnb's rule to export a single thing per file (which I actually agree with, I just disagree with using default at all due to harm it causes). Commented Mar 25, 2019 at 14:32
  • I think the spirit of Airbnb's rule is to avoid multiple exports per file (an object/namespace containing multiple things is still only one export), although I might be wrong. Anyway, I guess you can post your answer, which is "You can't mix types and values in a default export object". Commented Mar 25, 2019 at 14:48
  • 2
    Rather than asking why the OP wants to do this, why not answer the question, why does TS disallow this? Seems like such a comment might be more useful, rather than deflecting the question down a rabbit hole of opinions. In the meantime I'll assume the reason no one explained why TS disallows this, is because there's no good reason and it is simply a shortcoming of the language. Commented Apr 2, 2020 at 20:54

3 Answers 3

8

Consider export = syntax.

The export = syntax specifies a single object that is exported from the module. This can be a class, interface, namespace, function, or enum.


Vehicle.ts

namespace Vehicle {
    export class Car {
        // ...
    }

    export class Bus {
        // ...
    }
}

export = Vehicle;

Test1.ts

import Vehicle from './Vehicle';

const car = new Vehicle.Car();
const bus = new Vehicle.Bus();

Test2.ts

import { Bus, Car } from './Vehicle';

const car = new Car();
const bus = new Bus();

See https://www.typescriptlang.org/docs/handbook/modules.html#export--and-import--require

Sign up to request clarification or add additional context in comments.

3 Comments

But this isn't the same as export default...
Of course it's different. But this syntax solves the problem described in the question. Another issue is that this syntax is only supported by the "СommonJS" and "AMD" modules. I see that many libraries are now moving to ESM where this syntax will not work. So it is better not to use this syntax and look towards ESM.
I don't think this is a good suggestion since it does not work in ESM nor does it utilize the default
2

In fact, by exporting like so:

class Car {...}
interface Motorcycle {...}

// 'Airplane' only refers to a type, but is being used as a value here. ts(2693)
export default { Car, Airplane }

What you do is to **export a default object with two properties*.*

Later, in your code, you can import it like so:

// name is as you like, its default import
import transport from transport;

and use it like so:

....new transport.Car()
....new transport.Plane()

1 Comment

This makes perfect sense to me. The mozilla/webextension-polyfill WebExtension browser API Polyfill uses namespaces extensively and I was wondering why eslint was complaining when I tried to copy its style to group interfaces and types. Using namespaces this way has really helped me avoid the Smurf Naming Convention anti-pattern. It's better to import the namespace than each smurf named type individually, then qualify the simplified type name by its namespace.
1

You actually can have a default export of multiple types and values by having a helper file with named exports only and then exporting everything from that file as default.

For example:

// named-exports.ts
export interface Vehicle {...}
export class Car {...}
export class Airplane {...}
// default-export.ts
export * as default from "./named-exports";

You can now import everything from default-exports and refer both to types and values.

For example:

// usage-example.ts
import Transport from "./default-export";
let car: Transport.Vehicle = new Car();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.