Using Typescript? Time to start barreling.

It won’t be long until the next time you have to refactor your React/Vue/Angular/Typescript app. The barrel feature helps make it easier.

Barreling is a neat feature in Typescript that allows a single file to group (or barrel) the components within its directory tree into a new, custom set of exports. It’s a great tool that will save you time and headaches during your next inevitable refactoring! It also allows you to write cleaner, more understandable import statements in fewer lines of code. Let’s take a look at barreling!

Simplifying import statements

Suppose you have 4 components all nested somewhere under the `src/components` directory:

1.	// src/components/common/buttons/bigButton
2.	export BigButton.tsx
3.	 
4.	// src/components/common/buttons/animated/spinnyButton
5.	export SpinnyButton.tsx
6.	 
7.	// src/components/common/baseButton
8.	export BaseButton.tsx
9.	 
10.	// src/components/specialButtons/specialButton
11.	export SpecialButton.tsx  
If I wanted to use these 4 components anywhere, I’d need 4 separate import statements each pointing to the individual file that contains the component. Like this:
1.	// src/App.tsx
2.	import { BigButton } from “./components/common/buttons/bigButton”
3.	import { SpinnyButton } from “./components/common/buttons/animated/spinnyButton”
4.	import { BaseButton } from “./components/common/baseButton”
5.	import { SpecialButton } from “./components/specialButtons/specialButton” 
With barreling, I can import all these components using just 1 import statement.

How to Barrel

There are 3 steps to creating a barrel in your Typescript application.

Three Steps:

    1. Create a file called index.ts in a directory that contains all your related components — It has to be called “index”.
    2. In index.ts, create export statements for all your desired components
    3. When importing, simply choose the directory the index.ts file resides in.

Simply add a file called index.ts to the components directory. Index.ts has visibility now of every component under components.

1.	// components/index.ts
2.	export { BigButton } from “./common/buttons/bigButton”
3.	export { SpinnyButton } from “./common/buttons/animated/spinnyButton”
4.	export { BaseButton } from “./common/baseButton”
5.	export { SpecialButton } from “./specialButtons/specialButton”  
Now when importing you can simply refer to the directory that index.ts resides in instead each individual file that contains the components you’re interested in. In this case, the directory that index.ts resides in is “/components”.

So, importing could now look like this:

1.	// src/App.tsx
2.	import { BigButton, SpinnyButton, BaseButton, SpecialButton } from “./components”  
This works because when an import statement only refers to the directory name, Typescript knows by default to look for a file called index and retrieve exports from there. This will make your imports cleaner and more readable.

Creating single export source

Continuing with our example files and components above, suppose you needed to change the name of the common directory from “/common” to “/core/v1/common”. Barreling reduces the scope of this change to updating 1 file instead of updating files all over your application.

An update like changing “/common” to “/core/v1/common” would absolutely break this code. To fix it without barreling you would need to locate every file that contains an import path with “/common” and update it:

1.	// every file that refers to the common directory would need to be updated
2.	import { BigButton } from “./components/core/v1/common/buttons/bigButton”
3.	import { SpinnyButton } from “./components/core/v1/common/buttons/animated/spinnyButton”
4.	import { BaseButton } from “./components/core/v1/common/baseButton”
5.	...
6.	import ... from “.../core/v1/common/..." 
But with barreling, you only need to update the index.ts file. All other files importing from your index file wouldn’t need to be touched.
1.	// components/index.ts
2.	export { BigButton } from “./core/v1/common/buttons/bigButton”
3.	export { SpinnyButton } from “./core/v1/common/buttons/animated/spinnyButton”
4.	export { BaseButton } from “./core/v1/common/baseButton”
5.	export { SpecialButton } from “./specialButtons/specialButton” 
This is because all other files, under the barreling pattern, are referring to the parent directory. In this case, “./components”.
1.	// src/App.tsx, which doesn’t need to be changed!
2.	import { BigButton, SpinnyButton, BaseButton, SpecialButton } from “./components” 

Barrels containing other barrels

In our examples above, you’ll notice that we’re still using separate import statements for components that are both in the “/core/v1/common/buttons” directory. We can put those in a barrel!

1.	// components/core/v1/common/buttons/index.ts
2.	export { BigButton } from “./bigButton”
3.	export { SpinnyButton } from “./animated/spinnyButton” 
We could then update our “/components/index.ts” file to import from the barrel that now exists in the “core/v1/common/buttons” directory:
1.	// components/index.ts importing BigButton and SpinnyButton from a barrel
2.	export { BigButton, SpinnyButton } from “./core/v1/common/buttons”
3.	export { BaseButton } from “./core/v1/common/baseButton”
4.	export { SpecialButton } from “./specialButtons/specialButton” 
You could even barrel all components under the “./core/v1/common” directory and then import it in the same way you imported from “components/core/v1/common/buttons/index.ts”
1.	// components/core/v1/common/index.ts
2.	export { BaseButton } from “./baseButton”
3.	export { BigButton } from “./buttons/bigButton”
4.	 
5.	// components/index.ts
6.	export { BigButton, SpinnyButton, BaseButton } from “./core/v1/common”
7.	export { SpecialButton } from “./specialButtons/specialButton” 

More barreling options

You don’t have to specify each component specifically. You could use an asterisk “*” to refer to all components in that path:

1.	// components/index.ts exporting everything
2.	export * from “./core/v1/common”
3.	export * from “./specialButtons/specialButton”
4.	 
5.	// src/App.tsx
6.	import { BigButton, SpinnyButton, BaseButton, SpecialButton } from “./components” 
You can export components under a different name. Doing this would cause the imports to require the updated name.
1.	// components/index.ts exporting everything with different names
2.	export { BigButton as BButton, SpinnyButton as SpButton, BaseButton as BaButton} from “./core/v1/common”
3.	export { SpecialButton} from “./specialButtons/specialButton”
4.	export { SpecialButton as AnotherSpecialButton} from “./specialButtons/specialButton”
5.	 
6.	// src/App.tsx
7.	import { BButton, SpButton, BaButton, SpecialButton, AnotherSpecialButton } from “./components” 
You can pick a component to export as default
1.	// components/index.ts
2.	export { BigButton, SpinnyButton as default, BaseButton } from “./core/v1/common”
3.	export { SpecialButton } from “./specialButtons/specialButton”
4.	 
5.	// src/App.tsx
6.	import SpinnyButton, { BigButton,BaseButton, SpecialButton } from “./components” 

Conclusion

Barreling gives you much greater control over your application architecture. It’s ability to allow files to import from the directory level instead of the file level allows greater flexibility during refactors. The level to which you barrel up your application is up to you!

Author

Luis Camacho III – Intertech, Inc Consultant
Luis Camacho describes himself as “your friendly neighborhood full-stack engineer.” His goal? Making things more efficient and creating tools that make people’s lives better. That’s precisely what Luis has done since he joined Intertech in July of 2019. Previously he was a lead software engineer at Emerson, where he provided consultation for an in-house innovation team and overhauled the release process, saving more than 100 development hours annually.

About Intertech

Founded in 1991, Intertech delivers software development consulting to Fortune 500, Government, and Leading Technology institutions, along with real-world based corporate education services. Whether you are a company looking to partner with a team of technology leaders who provide solutions, mentor staff and add true business value, or a developer interested in working for a company that invests in its employees, we’d like to meet you. Learn more about us.