JavaScriptでTypedArrayかどうかを判定する方法をまとめました。
意外とどうしたらいいのかわからなくて困りましたからね。
1. 正規表現
正規表現を使う方法です。
babelのランタイム関数 _unsupportedIterableToArray でも似たような正規表現が使われていたりします。1
この方法は今後この正規表現でカバーできないTypedArrayが追加された場合、更新する必要があります。
流石にもうない気がしますが。
また、Object.prototype.toString
と正規表現に依存しているので、@@toStringTag
に正規表現にマッチする文字列が入っていたら誤判定します。
const toString = Object.prototype.toString;
const regexp = /^(Big)?(Uin|In|Floa)t(8|16|32|64)(Clamped)?Array$/;
const isTypedArray = (value) => (
regexp.test(toString.call(value))
);
// 誤判定するケース
isTypedArray({
[Symbol.toStringTag]: "BigFloat8ClampedArray"
}); // > true
2. %TypedArray%
全てのTypedArrayは%TypedArray%
を継承しているので、%TypedArray%
のインスタンスかを調べる方法です。
有効でない%TypedArray%
のインスタンスもtrueなんですが、%TypedArray%
はそもそもエラーで呼べないのでObject.create(%TypedArray%.prototype)
でないと作れません。このくらい許しましょう。
const $TypedArray$ = Object.getPrototypeOf(Int8Array);
const isTypedArray = (value) => (
value instanceof $TypedArray$
);
// 誤判定するケース
isTypedArray(Object.create($TypedArray$.prototype));
3. ArrayBuffer.isView
ArrayBuffer.isView
を使っています。
ネイティブで[[ViewedArrayBuffer]]を持っているか確認しているので、一番堅牢な方法だと思います。
TypedArrayとDataView以外にArrayBuffer.isView
がtrueを返すオブジェクトが追加されたら更新しないといけませんが、まあないでしょう。
仕様書:https://tc39.es/ecma262/#sec-arraybuffer.isview
const isTypedArray = (value) => (
ArrayBuffer.isView(value) && !(value instanceof DataView)
);
// 誤判定するケースは思いつきませんでした。多分ないと思います。
4. constructor
TypedArrayの配列を作ってconstructorと比較する方法です。
これだとconstructorが上書きされていたりTypedArrayを継承したクラスを判定できません。2
それぞれにinstanceofするように変えてもそれ2番目のでよくね?となります。
また、BigInt64Arrayなどの最近の仕様にしか存在しないものは、対応していないブラウザなどでエラーが出ます。
他のを使いましょう。
const typedArrays = [
Int8Array,
Uint8Array,
Uint8ClampedArray,
Int16Array,
Uint16Array,
Int32Array,
Uint32Array,
Float32Array,
Float64Array,
BigInt64Array,
BigUint64Array,
];
const isTypedArray = (value) => (
typedArrays.includes(value.constructor)
);
// 誤判定するケース
isTypedArray({
constructor: Int8Array
}); // > true
class MyTypedArray extends Int8Array {}
isTypedArray(new MyTypedArray); // > false
// 代替案
const isTypedArray = (value) => (
typedArrays.some(ctor => value instanceof ctor)
);
typescript
最後におまけとしてTSの型を置いておきます。
type TypedArray = (
| Int8Array
| Uint8Array
| Uint8ClampedArray
| Int16Array
| Uint16Array
| Int32Array
| Uint32Array
| Float32Array
| Float64Array
| BigInt64Array
| BigUint64Array
);
const isTypedArray = (value: unknown): value is TypedArray => (
// 実装
);
参考
https://tc39.es/ecma262/
https://stackoverflow.com/questions/58280379/how-to-find-the-type-of-a-typedarray
-
https://babeljs.io/replで
[...""]
とか書くと確認できると思います。 ↩ -
TypedArrayを継承して使うことなんてあるんでしょうかね? ↩