Answer a Question
Sign In

Use @Scope Paths For Shorter Import Paths Configurable In Tsconfig.json

Tuesday, November 12, 2019

Relative import paths in large applications can quickly become difficult, and well, long. To avoid long and difficult relative import paths the TypeScript compiler providers the path option to specify common and often-used import paths in your application.

To enable import paths you first must specify the baseUrl compiler option:

{
  "compilerOptions": {
    "baseUrl": "./"
  }
}

Then, specify the paths compiler option. Here is an example of compiler options for several root modules that use barrel files for exporting all child modules within the directory:

{
  "compilerOptions": {
    "baseUrl": "./",
    "paths": {
      "@app-core/*": ["src/app/core/*"],
      "@app-features/*": ["src/app/features/*"],
      "@app-material/*": ["src/app/material/*"],
      "@app-shared/*": ["src/app/shared/*"],
      "@app-state/*": ["src/app/state/*"]
    }
  }
}

Instructions

  • Do:

    specify paths to commonly used modules in the tsonfig paths compiler option

  • Do:

    specify the baseUrl compiler option

  • Do:

    use barrel files to keep import paths even shorter

  • Avoid:

    long relative import paths

  • Why:

    barrel-based import paths are clean and easy to maintain

Avoid

long relative import paths

import React, { Component } from 'react';
import { render } from 'react-dom';
import { User } from '../../../../models/user.model';
import { UserService } from '../../../../services/user.service';
import Hello from './Hello';
import './style.css';

enum AccessLevel {
  User,
  Editor,
  Admin
}

interface AppProps { }
interface AppState {
  user: User;
}

class App extends Component<AppProps, AppState> {
  constructor(props) {
    super(props);
    this.state = {
      user: null
    }
  }

  componentDidMount () {
    const { id } = this.props.match.params

    this.userService.getUserById(id)
      .then((user) => {
        this.setState(() => ({ user }))
      })
  }

  render() {
    return (
      <div>
        <Hello name={this.state.user.displayName} />
      </div>
    );
  }
}

render(<App />, document.getElementById('root'));

Do

use barrel files and path based imports

import React, { Component } from 'react';
import { render } from 'react-dom';
import { User } from '@unicorn/models/user.model';
import { UserService } from '@unicorn/services/user.service';
import Hello from './Hello';
import './style.css';

enum AccessLevel {
  User,
  Editor,
  Admin
}

interface AppProps { }
interface AppState {
  user: User;
}

class App extends Component<AppProps, AppState> {
  constructor(props) {
    super(props);
    this.state = {
      user: null
    }
  }

  componentDidMount () {
    const { id } = this.props.match.params

    this.userService.getUserById(id)
      .then((user) => {
        this.setState(() => ({ user }))
      })
  }

  render() {
    return (
      <div>
        <Hello name={this.state.user.displayName} />
      </div>
    );
  }
}

render(<App />, document.getElementById('root'));
Brian Love
Brian is a software engineer and Google Developer Expert in Web Technologies and Angular with a passion for learning, writing, speaking, teaching and mentoring. He regularly speaks at conferences and meetups around the country, and co-authored "Why Angular for the Enterprise" for O'Reilly. When not coding, Brian enjoys skiing, hiking, and being in the outdoors. Brian recently launched lookout.dev where you can find best practices and expert advice on topics ranging from TypeScript, Angular, React, Node.js and more.
Google Developers Expert

Whoa 🤚 You need to sign in to join the discussion.

Don't worry, if you start a comment, we'll save it for when you return. 😉