Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
6
Help us understand the problem. What is going on with this article?
@kyokoshimizu

Angularでstrict: trueにした。(完結編)

More than 1 year has passed since last update.

こんにちは、清水です。

先月、Angularでstrict: trueにした。(strictNullChecks, strictPropertyInitialization編)
ていうブログを書きましたが、その完結編です。

strict: true になりました

無事にstrict: trueにする対応終了しました👏平成最後にできてよかったです
前回書いたstrictNullChecks, strictPropertyInitializationの対応を終えると、初期値や型を整理したプロパティを使用している側の修正がメインとなりました。
どんな箇所でエラーがよく出ていたかを紹介します。

null,undefinedの使い方が整理されてない

バラバラで全然よくない例
name?: string;
selectedId: string | null = null;

constructor(hogeService: HogeService) {
  this.hogeService.get<Hoge>(this.selectedId) // TS2345 Argument of type 'string | null' is not assignable to parameter of type 'string'.
    .subscribe((res) => {
      this.name = this.getFullName(res); // TS2322 Type 'string | null' is not assignable to type 'string | undefined'.
    });
}

getFullName(resource?: { last_name: string, first_name: string }): string | null {
    if (!resource) { return null; }
    ...
}

もともとプロパティの初期値が整理されていなかったので、当然プロパティを使う側の処理のnull, undefinedの使い方もバラバラでした。
上の例だと、次のようなことが起きてしまっています。
- HogeService#getはstring型の引数を期待しているけどselectedIdはnullableである
- nameはオプショナルだけど、getFullNameの戻り値がstring | null になってしまっている
このような整理されてない処理を、プロパティの型を元に改修しました。

オプショナル, nullableなプロパティへのアクセス

resource: { name: string } | null = null;
resources: string[] = [];
max?: number;
selectedNumber?: number;

this.resource.name // TS2531 Object is possibly 'null'
this.max > 0 // TS2532 Object is possibly 'undefined'
this.resources[selectedNumber] // TS2538 Type 'undefined' cannot be used as an index type

値がない場合の考慮漏れが多々あったので、条件分岐の追加やデフォルト値の設定をしました。

条件分岐処理での考慮漏れ

let amount: { total: number, consumption_tax: number };
let summary: number;
switch (this.type) {
  case 'car':
    amount = { total: 1000, consumption_tax: 80 };
    break;
  case 'house':
    amount = { total: 2000, consumption_tax: 160 };
    break;
}

summary = amount.total + amount.consumption_tax; // TS2454 'amount' is used before being assigned.

上の例だと、typeが 'car' 'house' 以外の場合の考慮漏れがありTS2454のエラーが出ます。
switch文での改修ではdefault節を追加して対応しました。
このようなエラーが事前にわかるとバグを防いでくれていいなと感じました。

RxJsを5から6にした時の修正もれ

import { Observable } from 'rxjs/Rx'; // TS2305 Module '"...../rxjs/Rx"'has no exported member 'Observable'.
Observable.timer(1).subscribe(() => { ... }); // TS2305 Property 'timer' does not exist on type 'typeof Observable'

strict: trueにしてよかったこと

不要なソースを消すことができた

エラー改修をするにあたり全体ソースを見直すことになったので、使ってないプロパティや不要な処理を大幅に消せました。

null, undefinedの整理

プロパティの初期値、それらを使う側での処理でnull, undefinedの使い分けが実装者の感覚で行われてしまっていた部分を整理することができました。

バグを埋め込みにくいソースになった

一番よかったのが、これです。
プロパティが意図しない使われ方をされにくくなったり、値がない場合の考慮漏れや条件分岐処理での漏れの検出が事前にできるようになったりしたため、バグを埋め込みにくい環境になりました。
また、エラー改修するうえで既存バグの検出&修正もできました。

まとめ

今だとAngular CLIで作成したprojectではデフォルトでstrict: true になっていますが、
まだfalseの人は早めに変更した方がいいと思います。 (←追記:すみません勘違いしてました。。)
strict対応をしようとしている人は、なるべく早くに対応したほうがいいと思います。
ただ、修正にはある程度工数がかかります。(ソース量にもよりますが)
ある箇所のエラーを直すと別な箇所で新たなエラーがでるといったぐあいなので、見積もりをする際にはきちんとバッファを積み余裕を持って修正を行うことをお勧めします。(ちなみに私は見積もりが甘すぎて辛い思いをしました笑)
あとは、null, undefinedの使い分けなどのチーム内の方針となるような部分は、チーム内で認識を合わせてながら改修を進めていくとやりやすかったです。

6
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
dmmcom
総合エンタテイメントサイト「DMM.com」を運営。会員数は2,900万人を突破。動画配信、FX、英会話、ゲーム、太陽光発電、3Dプリンタなど40以上のサービスを展開。沖縄での水族館事業参入、ベルギーでのサッカークラブ経営など、様々な事業を手掛ける。また2018年より若手起業家の支援を強化、「DMM VENTURES」による出資や、M&Aなどを積極的に展開している。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
6
Help us understand the problem. What is going on with this article?