1
0

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.

TypeScriptで関数の戻り値の型を推測して型定義する方法

Posted at

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

概要

TypeScriptで通常通り定義した関数の戻り値の型を推測した上で、新しい型として定義する方法を紹介します。

背景

TypeScriptを書いていて、この関数の戻り値の型って、他のところでも使いたいんだけど、わざわざtype構文で定義するのだるいしと、煩わしく思ったことがありませんでしょうか?

もしくは、戻り値の型と、他の関数の引数の型が微妙に違って、TypeScriptのインタープリターに警告を吐かれたこと、ありませんか?

このような経験を繰り返していると、TypeScript、にりーと思うようになって、TypeScriptの良さが伝わらないのです。

そこで、実は、助けになるUtilityTypeがあります。

ReturnTypeなのです。

使い方を説明していきましょう。

ReturnTypeの使い方

まず最初に、以下のようなコードを例に挙げます。

const theShining = ["RedRum", "All work and no play makes Jack a dull boy"];

const createListItemElements = (contents: string[]) => contents.map(content => {
    const li = document.createElement("li");
    li.classList.add("come-play-with-us-danny");
    li.textContent = content;
    li.addEventListener("click", () => alert(`List item ${content} was clicked!`), { once: true });
    return li;
});

我々は開発者として、文字列が入っている配列を<li class="come-play-with-us-danny">要素の配列に変換する関数を作るように指示を受けました。

また、その<li>の配列の各要素は、クリックすると、一回だけ、alertを出すようにするのだと。

その仕事が終わって、上司にこう言われました。

なんだか不気味な実装だが、よかろう。
<li>の配列をDOMにレンダーできるようにせぇ!

ReturnTypeの出番

指示を受けた我々は、すぐにそのロジックを書きました。

const renderListItems = (listElements: ReturnType<typeof createListItemElements>) => {
    const ul = document.querySelector("ul")!;
    ul.innerHTML = "";
    ul.append(...listElements);
};

そうです、かっこよくもReturnTypeを使うことでなんと -20秒 の作業時間を短縮できました。

さらに一歩進んで、以下のような型定義をすることができます。

type ScaryListElements = ReturnType<typeof createListItemElements>;

const addAnotherEventListener = (listElements: ScaryListElements) =>
    listElements.forEach(li => li.addEventListener("transitionend", () => console.log("Transition Ended.")));

const renderListItems = (listElements: ScaryListElements) => {
    const ul = document.querySelector("ul")!;
    ul.innerHTML = "";
    ul.append(...listElements);
};

普通にconst renderListItems = (listElements: HTMLLIElement[]) => {と書くことももちろんできました(その方もおそらく早かったでしょう)が、こうして、複数の他の関数等で使うことになったり、戻り値の型がややこしかったりすると、やはり、このUtilityTypeが優れた選手として活躍してくれます。

JavaScript環境で開発している時に、JSDocsでもできます。

TypeScriptを使うメンバーがいなかったり、プロジェクト全体でTypeScriptを導入することに及び腰だった場合、JSDocsを使ってTypeScriptの機能を活かすことができます。

JSDocsによるTypeScriptは、あくまでも単なるコメントなので、文句を言われる筋合いはない、というところが売りです。

上記のコードをJSDocs付きのJavaScriptに書き直すと以下のようになります。

//@ts-check
/** @typedef {ReturnType<typeof createListItemElements>} ScaryListElements  */

const theShining = ["RedRum", "All work and no play makes Jack a dull boy"];

/** @param {string[]} contents */
const createListItemElements = (contents) => contents.map(content => {
    const li = document.createElement("li");
    li.classList.add("come-play-with-us-danny");
    li.textContent = content;
    li.addEventListener("click", () => alert(`List item ${content} was clicked!`), { once: true });
    return li;
});

/** @param {ScaryListElements} listElements */
const addAnotherEventListener = (listElements) =>
    listElements.forEach(li => li.addEventListener("transitionend", () => console.log("Transition Ended.")));

/** @param {ScaryListElements} listElements */
const renderListItems = (listElements) => {
    const ul = /** @type {HTMLUListElement!} */ (document.querySelector("ul"));
    ul.innerHTML = "";
    ul.append(...listElements);
};

こうするだけで上記のTypeScriptと同じようなIntellisenseと型チェックができるので、JSDocsは最高ですよ!

まとめ

ここまで、ReturnTypeの使い方を説明してまいりましたが、いかがでしょうか?

TypeScriptは使えば使うほど、苦手意識がなくなって、好きになってくるものです。

こういう便利ツールを駆使していくと、どんどんTSプロになっていきます。

1
0
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?