6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

AngularでTypeScriptのインポートエイリアスを使う

Posted at

はいさい!ちゅらデータぬオースティンやいびーん!

概要

Angularでモジュールのインポートにエイリアスを付けるTypeScript機能を使う方法を紹介します。

背景

Angularの正式ドキュメントで「ヒーローのアプリケーションを作る」のガイドをやっている時に、「AngularでTypeScriptのエイリアスをどうやってつけるのだろう」と気になったので試験的に設定してみたら案外簡単だったので、共有したくなりました。

インポートエイリアスとは

ESモジュールをインポートする時に、通常、相対的パスでインポートします。

しかし、サブダイレクトリが増えてくると、import { helperA } from "../../../../../../helpers.js"のように、とてつもなく長くなってしまいかねないのです。

また、helpers.jsを移動させたら、大変なことに。

こういう問題を解決するために、インポートエイリアスという機能がTypeScriptにあります。

上記のhelper.jsのエイリアスを以下のようにtsconfig.jsonで設定します。

{
    "compilerOptions": {
        "baseUrl": "./",
        "paths": {
          "@helpers": ["helper.js"]
        }
    }
}

すると先ほどのインポート構文が以下のように短くなります。

import { helperA } from "@helpers";

これがインポートエイリアスなのです。

Angularでインポートエリアスを使う

Angularでインポートエイリアスを使うのは簡単です。上記の例と同じようにtsconfig.jsonpathsの設定を追加すればできます。

Webpackと違って、Angularはtsconfig.jsonを見てくれますので特別な設定は不要です。

ガイドのヒーローアプリケーションを作った前提で進めます!

typesのフォルダーにHeroの型を入れます。

上記のガイドではsrc/app/hero.tsHeroの型定義をエクスポートしていたのだと思いますが、今回は、src/typesというフォルダーを作り、そこにhero.tsを移動させます。

src/types/hero.ts
export interface Hero {
  id: number;
  name: string;
}

tsconfigを変更する

次、上記で作ったフォルダーのエイリアスをtsconfig.jsonで指定します。

tsconfig.json
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
  "compileOnSave": false,
  "compilerOptions": {
    "baseUrl": "./",
    "outDir": "./dist/out-tsc",
    // ここです
    "paths": {
      "@custom-types/*": ["src/types/*"]
    },
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "noImplicitOverride": true,
    "noPropertyAccessFromIndexSignature": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "sourceMap": true,
    "declaration": false,
    "downlevelIteration": true,
    "experimentalDecorators": true,
    "moduleResolution": "node",
    "importHelpers": true,
    "target": "es2020",
    "module": "es2020",
    "lib": ["es2020", "dom"]
  },
  "angularCompilerOptions": {
    "enableI18nLegacyMessageIdFormat": false,
    "strictInjectionParameters": true,
    "strictInputAccessModifiers": true,
    "strictTemplates": true
  }
}

このエイリアス定義だと、typesの中に入るすべてのファイルが使えるのでおすすめです。

なお、@types/*じゃなくて@custom-types/*と指定していることに気づかれた読者もいるかと思いますが、これには理由があります。

  1. 明示的にこのプロジェクトで追加した型なのだというニュアンスを伝えたいから。
  2. TypeScriptのnode_modules@typesとコンフリクトする から

@types/で指定すると以下のようなエラーがTSインタプリターから吐かれますのでご注意を。

Cannot import type declaration files. Consider importing 'hero' instead of '@types/hero'

エイリアスでインポートする

上記の変更を保存すれば、最後に、Heroがインポートされているファイルをすべて以下のようにエイリアスを使うように修正する必要があります。

src/app/heroes/heroes.component.ts
import { Component, OnInit } from '@angular/core';
// こうして普通のエイリアス構文でインポートすれば後はAngularがやってくれます!
import { Hero } from '@custom-types/hero';
import { HeroService } from '../hero.service';
import { MessageService } from '../message.service';

@Component({
  selector: 'app-heroes',
  templateUrl: './heroes.component.html',
  styleUrls: ['./heroes.component.css'],
})
export class HeroesComponent implements OnInit {
  public heroes: Hero[] = [];
  public selectedHero?: Hero;
  protected heroesSubscription!: ReturnType<
    ReturnType<InstanceType<typeof HeroService>['getHeroes']>['subscribe']
  >;

  constructor(
    private heroService: HeroService,
    private messageService: MessageService
  ) {}

  ngOnInit(): void {
    this.getHeroes();
  }

  protected getHeroes() {
    this.heroesSubscription = this.heroService
      .getHeroes()
      .subscribe((heroes) => {
        this.heroes = heroes;
      });
  }

  public handleSelection(hero: Hero): void {
    if (hero.id === this.selectedHero?.id) {
      this.messageService.add('HeroesComponent: Hero unselected.');
      return (this.selectedHero = undefined);
    }
    this.messageService.add(`HeroesComponent: Selected ${hero.name}.`);
    this.selectedHero = hero;
  }
}

全てを変更し、保存してみると、エラーが消えてちゃんとコンパイルされるはずです!

まとめ

ここまで、AngularでTypeScriptのインポートエイリアスを使う方法を紹介しましたがいかがでしょうか?

tsconfig.jsonを変更するだけであとは何もしなくていいというところがとても好きです。

Webpackでは、最初にエイリアスを設定する時にかなり苦労した記憶があります。

ViteとAstroも同じような仕組みで、tsconfig.jsonで一度設定すれば、他のややこしい設定はないのです。

おまけ:Angularについての感想

Angularはかなり過小評価されているライブラリだと思いました。

なぜこれまでにアンチされているのか理解ができません。

Vueのように学習ハードルが低いけれど、Vueよりもツールが豊富で、全体的にオブジェクト指向のアプリケーション設計ができるようになっていてコードを整理しやすいと思います。

また、フレームワークでできる書き方に制限をかけていて、よく言えばジュニアのエンジニアでも変な書き方ができないようになっています。

悪く言えば書き方に融通が効かない、硬い感じがするのでしょうか?

クラス構文を採用しているのと、明確なライフサイクルがあるので、その中でできないことはないと筆者は思いますが、なんでヘイトされているのだろうか。

筆者は、全体的にモダンなWeb開発はDOMとブラウザ機能からかけ離れているのが良くないと思っており、Vue、Angular、LitといったライブラリのようにJavaScriptのバニラ機能を活かしているフレームワークが魅力的に感じます。

6
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?