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

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

新規登録して質問してみよう
ただいま回答率
85.50%
アルゴリズム

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

TypeScript

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

Q&A

解決済

1回答

3016閲覧

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

kxphotographer

総合スコア37

アルゴリズム

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

TypeScript

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

2グッド

1クリップ

投稿2016/04/22 13:37

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

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

TypeScript

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

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

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

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

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

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

fundidididi, ikuwow👍を押しています

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

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

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

TypeScript

1const cartesianProductOf = <T>(...items: T[][]) => { 2 return _.reduce(items, (a: T[][], b: _.Dictionary<T>) => { 3 return _.flatten(_.map(a, (x: T[]) => { 4 return _.map(b, (y: T) => { 5 return x.concat([y]); 6 }); 7 }), true); 8 }, [[]]); 9};

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

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

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

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

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

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

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

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

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

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

投稿2016/04/24 06:35

ps13zier

総合スコア433

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kxphotographer

2016/04/29 22:31

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問