質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.49%

  • アルゴリズム

    420questions

    アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

  • TypeScript

    353questions

    TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

TypeScriptで直積の関数を貼り付けたらエラーが出ました

解決済

回答 1

投稿

  • 評価
  • クリップ 1
  • VIEW 1,850

kxphotographer

score 31

今日、今まで使っていたCoffeeScriptに代わってTypeScriptを触り始めました。実際にブラウザでJavaScriptを動かす前から具体的にプログラムの不備に気付けたりと、静的型付けの強みを身にしみて感じているところです。

さて、あるプログラムで複数の配列の直積(すべての組み合わせ)を取得したいと思い、Underscore.jsを使用しStackOverflowの記事を参考にTypeScript用に書き換えてみました。
すると、下記のコメントの行の無名関数の引数の部分でエラーが出ました。

/// <reference path="../typings/main.d.ts" />
var cartesianProductOf = (...items: any[]) => {
  return _.reduce(items, (a, b) => {
    return _.flatten(_.map(a, (x) => {
      return _.map(b, (y) => { // この行の_.mapの第1引数"b"でエラー
        return x.concat([y]);
      });
    }), true);
  }, [[]]);
};

エラー内容は以下の通りです。

Argument of type '{}' is not assignable to parameter of type 'Dictionary<{}>'.
  Index signature is missing in type '{}'.

Underscore.jsの型定義はtypingsで読み込んであります。

おそらく中身の無名関数の引数に型を定めていないことによるものかと思います。
しかしいざ型を指定しようとも、この関数からどのようにして直積が求まるのか、仕組みがよく理解できていません。

各無名関数にはどういった型を設定するのが適当か、またこの関数たちがどのように作用しあって最終的に直積が求められるのか、ご教授頂ければ幸いです。よろしくお願い致します。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+2

私もちょうど数日前から TypeScript を勉強し始めたので、提示されているコードを試してみたところ、同じようにエラーが出るのを確認しました。

解決例を先に示します。厳密にする場合、たぶん、以下のような定義で型の部分の問題は解決すると思います。

const cartesianProductOf = <T>(...items: T[][]) => {
  return _.reduce(items, (a: T[][], b: _.Dictionary<T>) => {
    return _.flatten(_.map(a, (x: T[]) => {
      return _.map(b, (y: T) => {
        return x.concat([y]);
      });
    }), true);
  }, [[]]);
};


Dictionary の部分は List でも動くかも?reduce() と map() で共通していた Dictionary で定義しました。あと、そのまま書くのは面白くなかったので Generics (ジェネリック/総称型) を使って定義してみました。これを上手く利用すると配列の中身を数値だけに限定したい場合など、TypeScript の型チェックが効果的に使えるようになります。

例えば、以下のように書いた場合、文字列部分を含む配列がエラーとみなされます。

cartesianProductOf<number>([1,2], ['a',20])

実際使うかどうかは解りませんが number 部分を string や Object や Function なんかに変えたり色々できますね。

少々話が脱線しましたが、質問にある『どういった型を設定するのが適当か?』という問題は堅めの言語を齧ってない人には結構難しい問題なのかもしれません。

型を特定する策として(邪道だとツッコミが入るかもしれませんが)今回の場合だと、map 部分の引数 b の型が不明瞭なわけですが、もうそのまま b as any にするとか、型でエラーが出ている箇所全てを any にして(型を無視して)しまい、手っ取り早くコードが動く状態を作った上で、開発環境からステップ実行して実際の型を調べたり、適切な箇所において引数や処理結果をコンソールに出力して調べたり、typings で取ってきた型定義を直接調べたり。といった作業を繰り返し、解った所からどんどん any を排除していくのが手探り状態でもできる一つの方法でしょう。大変に泥臭い方法ですが、言語仕様を理解できており、ライブラリに対する型定義自体が整備されていれば、あとは地道に動かしながら調べさえすれば、自ずと答えを求められるようになるのではないでしょうか?

というのも、自分が1から書いているコードであれば、都度使うべき型は明確である/明確にできると思いますが、型が省略されている他人の書いたコードで、更に動かせない。となると、なかなか手が出しづらいのも納得できる話です。コードを目で読んだだけで解るレベルに到達するのは、コードの内容に準じたスキルを持っていないと厳しい。と私は思っているため、拾ってきたコードなりで勉強するのであれば、動かせる状況を早めに作り、実際に動かしながら手を入れていく方が理解も深まりやすいでしょう。

今回のコードの場合だと、アロー関数式が使われていますし、Underscore.js の型定義を調べてみたところ、ジェネリックが多用されていました。逆に、この辺の言語仕様が正しく理解できているのであれば時間をかけさえすれば読み解けますので、後はパズルを解くように順に調べれば良いだけです。物は試しに自分で解いてみるとよいでしょう。解らない点が出てくれば、そこがまた伸ばすべき箇所です。

もう一つの質問である関数内部の詳細な挙動に関して、このコードは『極めて素直』なので、動く状態さえ作れれば確認自体は簡単なハズです。また、Underscore.js の reduce() / flatten() / map() が、それぞれどのような機能なのかを調べ、個別に叩くことで更に理解も深まると思います。もし、そこまで行った上で解らない箇所があれば、要件を絞って改めて質問を投げてみてはどうでしょうか?まずはコードを叩いて自分で確認してみましょう。

以上、ご参考になれば幸いです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/04/30 07:31

    ジェネリック型に関してはJavaを扱った時におまじない程度に使っていたくらいで、今回はじめてジェネリック型という名前と使い方を学ぶことができました。
    動きそのものについてはまだ完全に理解はできていませんが、すべてのアロー関数の引数と戻り値についてエラーの出ない型宣言を書く事ができました。より処理が追いやすくなっていると思うので、頑張って理解してみようと思います。

    ご丁寧な回答を誠にありがとうございました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.49%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • アルゴリズム

    420questions

    アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

  • TypeScript

    353questions

    TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。