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

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

新規登録して質問してみよう
ただいま回答率
85.35%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

TypeScript

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

Q&A

解決済

3回答

294閲覧

TypeScript 5.5のfilterで型が絞り込めない

hupyaginu

総合スコア16

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

TypeScript

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

1グッド

1クリップ

投稿2024/09/30 05:04

編集2024/09/30 05:21

発生している問題

filteredNames1, filteredNames2, filteredUserNames2は期待通りの動作をしています。
しかし、filteredUserNames1は型が (string | null)[] のままになっており、nullが消えていません。
string[]になる事を期待していました。

filterを先に実行してからmapを実行したい場合も今後あると思います。
filterを後に書かなければ現状型が正しくありません。
filterを先に書いても型が正しくなる方法はありますか?
それとも、filterを先に書いた場合はnullになる事がありえるのでしょうか?(私は無いと思っていますが)

該当のソースコード

TypeScript Playground

typescript

1 2const names = [ 'a', 'b', null] 3 4const filteredNames1 = names 5 .filter(name => name !== null) 6 .map(name => name) 7// const filteredNames1: string[] 8 9const filteredNames2 = names 10 .map(name => name) 11 .filter(name => name !== null) 12// const filteredNames2: string[] 13 14// ----------------------------------- 15interface User { 16 id: number; 17 name: string | null; 18} 19 20const users: User[] = [ 21 { id: 1, name: '田中太郎' }, 22 { id: 2, name: '山田太郎' }, 23 { id: 3, name: null }, 24] 25 26const filteredUserNames1 = users 27 .filter(user => user.name !== null) 28 .map(user => user.name) 29// const filteredUserNames1: (string | null)[] 30 31const filteredUserNames2 = users 32 .map(user => user.name) 33 .filter(userId => userId !== null) 34// const filteredUserNames2: string[] 35 36

試したこと

  • 上記のようなサンプルプログラムを作成しました。実行結果からobjectの場合はfilterの順序が大事になってくると思いました。

補足情報(FW/ツールのバージョンなど)

  • TypeScript 5.6.2
takanaweb5👍を押しています

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

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

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

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

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

guest

回答3

0

自己解決

他のWebサイトで既に回答がありました
https://stackoverflow.com/questions/78756960

投稿2024/10/01 03:07

hupyaginu

総合スコア16

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

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

0

解説はどなかにお願いしたいですが(つまりよくわかってない)

typescript

1const filteredUserNames1 = users 2 .filter((user): user is {id: number, name: string} => user.name !== null) 3 .map(user => user.name)

filteredUserNames1string[] に推論されます

参考
https://blog.logrocket.com/filtering-typescript-value-types/#filtering-using-custom-type-guard-type-predicate

投稿2024/09/30 07:43

quickquip

総合スコア11235

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

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

hupyaginu

2024/10/01 02:54

確かに型指定してあげるとstring[]になりますね。 .map(user => user.name!) と書いても同じことが実現できそうです。 filterした時点で型が絞り込まれているのが理想ですが、そうはならないのですよね。。。
quickquip

2024/10/01 04:10

この filter で型が変わってしまうと const filteredUsers = users.filter(user => user.name !== null); filteredUsers.push(otherUser); が通らなくなってしまいます。それもどうかと思いますが……?? (otherUsers が Userのつもり)
maisumakun

2024/10/01 07:54 編集

> それもどうかと思いますが……?? 実際に、(string|null)[]などでfilterを行ってstring[]を抽出すると、そのような挙動になります。
quickquip

2024/10/01 04:24

確かにそうですね。どこかまではやる、どこかからは違和感がでる(人がいる)からやらない、というデザインの意思決定問題なだけですか
guest

0

filterを先に実行してからmapを実行したい場合も今後あると思います。

本題ではありませんが、flatMapを使えばfiltermapの両方をいっぺんにこなすことができますので、「filterを先に実行してからmapを実行したい場合」自体が発生しません。

ts

1const filteredUserNames1 = users 2 .flatMap(user => user.name === null ? [] : [user.name])

投稿2024/09/30 05:40

maisumakun

総合スコア146050

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

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

hupyaginu

2024/09/30 05:55 編集

回答有り難うございます。 maisumakun様が「本題ではありませんが」とおっしゃっている通り、確かにやりたい事は実現できますが、コードの読みやすさが悪くなります。 mapとfilterを組み合わせで実現したいです。 基本的にflatMapというメソッドを見ると配列の処理だと想像するはずです。 例えば [1,2,[3,4],5] を [1,2,3,4,5] にしたい時に使ったりを想像します。 flatMapでfilterのような処理をする事は普通考えないはずです。
maisumakun

2024/09/30 07:01

どうも、Type predicate inferenceは、「Foo | Bar」のような、トップレベルで複数選択となっている型だけに適用されて、Userのnameだけを絞り込む機能はなさそうです。 > flatMapでfilterのような処理をする事は普通考えないはずです。 それこそ、こんな記事もあります。 https://zenn.dev/spacemarket/articles/51613197db688d
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問