any 型で入ってきたデータのプロパティにアクセスしようとすると ESLint に怒られるので object 型だと判定したかった
value.foo
=> Unsafe member access .foo on an `any` value. eslint@typescript-eslint/no-unsafe-member-access
JavaScript の Object
オブジェクトを除くすべての型は、言語の最下層で直接表現される不変値を定義しています。これらの型の値を プリミティブ値 と呼びます。
cf. JavaScript のデータ型とデータ構造 - JavaScript | MDN
JavaScript のプリミティブ型
型 | typeof の返値 |
|
---|---|---|
Null型 | null |
"object" |
Undefined型 | undefined |
"undefined" |
論理型 | boolean |
"boolean" |
数値型 | number |
"number" |
長整数型 | bigint |
"bigint" |
文字列型 | string |
"string" |
シンボル型 | symbol |
"symbol" |
プリミティブ型以外は Object なので、Array も Function も Date も RegExp も Object という扱い
isObject 関数を作成する
Type Guard関数をユーザーが定義することができます。これは、someArgumentName is SomeTypeを返す関数です。
cf. 型ガード - TypeScript Deep Dive 日本語版
返り値が T is object
な Type Guard 関数を作成する
export const isObject(value: unknown): value is object => { const type = typeof value; return value !== null && (type == 'object' || type == 'function'); }
isObject
(Type Guard関数) が true
になる Object 型の変数のプロパティにアクセスできない問題
import { isObject } from './isObject'; if (isObject(myObj)) { myObj.foo; // ここで TypeError }
=> Property 'foo' does not exist on type 'object'. ts(2339)
object
型だが foo
プロパティがあるとは限らないので TypeError になっている
Type Guard の型を {[key: string]: unknown}
か Record<string, unknown>
にすれば良い
export const isObject(value: unknown): value is Record<string, unknown> => { const type = typeof value; return value !== null && (type == 'object' || type == 'function'); }
👇 これで Object のプロパティへのアクセスが OK になる
import { isObject } from './isObject'; if (isObject(myObj)) { myObj.foo; // OK }
{key: value}
なオブジェクトに限定したい場合は constructor
を使うと判別できる
JavaScript の Object は Array や function, Date なども含んでいて .
でプロパティにアクセスできるから問題は無いと思うが Type Guard の value is Record<string, unknown>
は厳密ではないよな〜って感じなので {key: value}
なオブジェクトで判定したい場合
export const isObject(value: unknown): value is Record<string, unknown> => { return value !== null && typeof value === 'object' && value.constructor === Object; }
cf. JavaScript `{}` なオブジェクトだけを判定したい - かもメモ
TypeScript化した
おわり
[参考]