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

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

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

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

Q&A

1回答

253閲覧

[TypeScript] タプルに対し`map()`メソッドを使った際の戻り値もタプルを維持したい

Nao.K

総合スコア40

TypeScript

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

0グッド

1クリップ

投稿2024/07/31 12:24

編集2024/08/01 01:45

実現したいこと

下記のような処理があるとします。

typescript

1const tuple = [ 2 {value: "a"}, 3 {value: "b"}, 4 {value: "c"}, 5] as const; 6 7const mappedTuple = tuple.map(e => e.value);

このとき、mappedTupleの型は["a", "b", "c"]ではなく("a" | "b" | "c")[]となります。

これを、["a", "b", "c"]で返すようなガード関数を作成したいのですが、なかなか上手く行っていません。

typescript

1// こういうのを作りたい 2const mapOfTuple = (tuple, callbackFn) => { 3 // map(と同様の)処理 4}; 5 6const mappedTuple2 = mapOfTuple(tuple, e => e.value); 7// 型が`["a", "b", "c"]`になる!

これを、タプルの要素数(大きさ)が任意長の場合にも適用できるようにしたいのです。

お知恵をお借りしたく、よろしくお願いいたします。

追記:
{value: "a"}のようなオブジェクトはあくまでも一例になり、実際はあらゆる値で成り立つようにと考えております。

typescript

1// 例えばこのようケースも 2const tuple: [number[], string[]] = [ 3 [1, 2, 3], 4 ["a", "b", "c"], 5]; 6 7const mappedTuple = mapOfTuple( 8 tuple, 9 e => e.reduce((acc, val) => acc + val), 10); // [number, string]

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

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

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

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

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

guest

回答1

0

mapと同じ、とはなりませんが、ひとまず目的を達成するには次のようなコードでどうでしょうか。

ts

1type TupleFromValueTuple<T extends readonly { value: string }[]> = { 2 [K in keyof T]: T[K] extends { value: infer V } ? V : never; 3}; 4 5function extractValues<T extends readonly { value: string }[]>(input: T): TupleFromValueTuple<T> { 6 return input.map(item => item.value) as TupleFromValueTuple<T>; 7} 8 9const tuple = [{ value: "a" }, { value: "b" }, { value: "c" }] as const; 10const output = extractValues(tuple); // readonly ["a", "b", "c"]

ややトリッキーなのは [K in keyof T]: T[K] extends { value: infer V } ? V : never; の部分かと思います。
infer を使って具体的な value の型を取得して同じキー(0, 1, 2)に同じリテラル型が設定されるようになっています。

投稿2024/07/31 17:08

mather

総合スコア6759

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

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

Nao.K

2024/08/01 01:32

回答いただき有難うございます! ちょっと書き方が足りなかったので申し訳ないです、、`{value: "a"}`のようなオブジェクトを挙げたのは一例のつもりでして、他の様々な値で汎用的な型を作りたいと思っておりました。。失礼しました... となりますと中々難しいのでしょうかね。。
mather

2024/08/01 10:09

汎用性を追求しようとすると [T1, T2, T3] のように入力の型が与えられたとき、 f : T1 -> U1 & T2 -> U2 & T3 -> U3 のようなポリモルフィックな関数が存在して [U1, U2, U3] という返り値の型が得られることになるのですが、そのような都合の良い関数 f が存在するかは T1, T2, T3 に共通する条件が必要になるかと思います。例えば、 { value: string } を部分型にもつ、 number[] のように + の演算で畳み込みができる、などです。 そのような共通性をきちんと型に折り込めば可能になるのではないでしょうか。 ちなみに、他の言語ではタプルには map が適用できないことが多いです。(値を並べたものであって、同一の型の値を持つ配列ではないため)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.34%

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

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

質問する

関連した質問