LoginSignup
3
2

More than 1 year has passed since last update.

オブジェクトを配列要素として持つ、配列型同士で構成される交差型は array.map での推論で失敗してしまう

Last updated at Posted at 2022-09-10

課題

タイトルの通り、下記のような交差(配列)型 HogePiyo に対して array.map でオブジェクトを取り出した場合、そのオブジェクト内に存在するはずのプロパティーが型情報として欠けてしまいます。これは TypeScript PlayGround でも確認する事ができます。

type Hoge = { hoge: number }[];
type Piyo = { piyo: string }[];
type HogePiyo = Hoge & Piyo;

const arrayHogePiyo: HogePiyo = [
    {
        hoge: 1,
        piyo: "a"
    }
];

// OK
const piyo = arrayHogePiyo[0].piyo;

// NG: Property 'piyo' does not exist on type '{ hoge: number; }'.(2339)
const arrayPiyo = arrayHogePiyo.map((item) => item.piyo)

解決方法

ものすごく単純ですが HogePiyo の型定義を下記のように変更します。

type Hoge = { hoge: number };
type Piyo = { piyo: string };
type HogePiyo = (Hoge & Piyo)[];

const arrayHogePiyo: HogePiyo = [
    {
        hoge: 1,
        piyo: "a"
    }
];

// OK
const arrayPiyo = arrayHogePiyo.map((item) => item.piyo)

結論

配列型同士を交差型にするのではなく、配列要素(オブジェクト)同士を交差型にして配列型を定義してください。この問題に対しては TypeScript - issues11961 でも取り上げられています。

// BAD(推論の結果が不透明であり、悪い定義)
type InterSectionArray = Hoge[] & Piyo[];

// GOOD
type InterSectionArray = (Hoge & Piyo)[];

余談(経緯)

お仕事で GraphQL Code Generator を使用しており、そいつが自動で生成してくれる型定義において、上記のような交差(配列)型と array.map 問題に当たってしまったので記事として残しました。自動生成による型定義の場合どうしようもないので、一旦下記のように解決しました。

// 自動生成された型
type BaseConnection = {
  edges: BaseEdge[]
}
type HogeConnection = {
  edges: HogeEdge[]
}
type Connection = BaseConnection & HogeConnection;
// 解決前: connection.edges の型が BaseEdge[] & HogeEdge[] なため array.map での推論に失敗
const idList = connection.edges.map((item) => item.id);

// 解決: as 句を使って (BaseEdge & HogeEdge)[] に cast する
const idList = (connection.edges as (BaseEdge & HogeEdge)[]).map((item) => item.id);
3
2
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
3
2