😛
TypeScriptでオブジェクトのリテラル型を扱う際の注意点を考察
TypeScriptでオブジェクトのリテラル型を扱う際の注意点を考察
オブジェクトのリテラル型の配列において各メソッドで型を絞れるか(Narrowing)を検証
まずはこんな型
type Action =
| {
type: "text";
id: string;
content: string;
}
| {
type: "amount";
id: string;
content: number;
}
| {
type: "route";
id: string;
path: string;
blank: boolean;
}
型を付けた配列を作成
const actions: Action[] = [
{
type: "text",
id: "foooooooooo",
content: "nob"
},
{
type: "amount",
id: "foooooooooo",
content: 800
},
{
type: "route",
id: "foooooooooo",
path: "/happy",
blank: true
}
];
いざ検証
/* find */
const routeAction = actions.find((action) => action.type === "route");
console.log(routeAction?.path); // NG
/* filter */
const routeActions = actions.filter((action) => action.type === "route");
console.log(routeActions[0]?.path); // NG
/* forEach */
actions.forEach((action) => {
if (action.type === "route") {
console.log(action.path); // OK
}
});
/* map */
actions.map((action) => {
if (action.type === "route") {
console.log(action.path); // OK
}
});
NGのものは
Property 'path' does not exist on type 'Action'. Property 'path' does not exist on type '{ type: "text"; id: string; content: string; }'.
という型エラーになっています.これはそれぞれpathプロパティがない場合があるよと言っています.
つまり型を
{
type: "route",
id: "foooooooooo",
path: "/happy",
blank: true
}
に絞り込むことができていないようです.
.filter
で絞り込めないのは結構きついものがある.
一応アノテーションで解決するとこうなります.
/* find */
const routeAction = actions.find(
(action) => action.type === "route"
) as Extract<Action, { type: "route" }> | undefined;
console.log(routeAction?.path);
/* filter */
const routeActions2 = actions.filter(
(action) => action.type === "route"
) as Extract<Action, { type: "route" }>[];
console.log(routeActions2[0].path);
うーん.
Discussion