TL;DR — すべての
Variantは型のタグを持っています。VarTypeはそれを数値で返し(vbDoubleは 5、vbStringは 8)、TypeNameは単語で返します("Double"、"String"、"Range")。Excel では、セルの値に付くタグを決めるのはコードではなく セル です。整数はDoubleとして、通貨の表示形式の数値は小数点以下 4 桁に丸められたCurrencyとして、日付の表示形式の数値はDateとして、エラーはErrorとして、複数セルの範囲は配列として届きます。タグを尋ねるのは、値がセルやユーザーの選択範囲、Variant型の引数から入ってくるコードの境界だけにして、それ以外の場所では本来の型を宣言してください。
Debug.Print TypeName(Range("A1").Value) ' Double, String, Date, Boolean, Error, Empty...
Debug.Print VarType(Range("A1").Value) ' 5, 8, 7, 11, 10, 0...
Debug.Print TypeName(Selection) ' Range, or ChartArea, Rectangle, Picture...
この記事は、値に「あなたは何者か」を尋ねる シリーズの第二回です。IsEmpty はひとつのタグを判定し、今回の VarType と TypeName はどんなタグでも読み取り、IsNull は「混在または不明」を意味するタグを判定します。シリーズを貫く考え方は、VBA の値は中身とは別に型のタグを持っていて、これらの関数は見た目ではなくタグを読んでいる ということです。
この記事で学べること
- 考え方の軸:タグを決めるのはコードではなくセル
- VarType の定数と TypeName の文字列
- 整数が Double になる理由と、通貨の表示形式がデータを丸める理由
- VarType はオブジェクトを通り抜け、TypeName はオブジェクトの名前を返す
- 単一セルと複数セルで変わる配列の落とし穴
- ユーザーが選択しているものを確認する
- どこで尋ね、どこで宣言するか
考え方の軸:タグを決めるのはコードではなくセル
Dim total As Double と書けば、型を決めるのはあなたです。ところが Range("A1").Value を読むときは違います。Excel が渡してくるのは Variant で、その中身を決めるのはセルです。同じ一行のコードが、ある行では数値を、次の行では文字列を、三行目ではエラーを、四行目では何もないものを受け取ります。
VarType と TypeName を使えば、その決定を行動に移す前に確かめられます。どちらも何も変換せず、失敗することもありません。タグを報告するだけです。
VarType の定数と TypeName の文字列
Excel の作業で出会うタグを、両方の名前で示します。
| セルまたは値 | VarType |
定数 | TypeName |
|---|---|---|---|
| 手つかずのセル | 0 | vbEmpty |
"Empty" |
| 混在または不明 | 1 | vbNull |
"Null" |
| あらゆる数値(42 も含む) | 5 | vbDouble |
"Double" |
| 通貨の表示形式の数値 | 6 | vbCurrency |
"Currency" |
| 日付の表示形式の数値 | 7 | vbDate |
"Date" |
| 文字列 | 8 | vbString |
"String" |
#N/A、#DIV/0! などのエラー |
10 | vbError |
"Error" |
| TRUE または FALSE | 11 | vbBoolean |
"Boolean" |
| 複数セルの範囲の値 | 8204 | vbArray + vbVariant |
"Variant()" |
Long 型の変数は 3(vbLong)、Integer 型は 2 を返し、オブジェクト変数に対して TypeName は "Range"、"Worksheet"、"Workbook"、"Nothing" などを返します。TypeName はどの言語の Office でも常に英語名を返すので(日本語版 Excel でも "Double" などの英語名です)、文字列と比較しても安全です。
タグの自然な使い方は、セルの種類ごとに処理を分ける Select Case です。
Sub DescribeCell(ByVal c As Range)
Dim v As Variant
v = c.Value
Select Case VarType(v)
Case vbEmpty: Debug.Print c.Address, "empty"
Case vbString: Debug.Print c.Address, "text: " & v
Case vbDouble, vbCurrency: Debug.Print c.Address, "number: " & v
Case vbDate: Debug.Print c.Address, "date: " & Format$(v, "yyyy-mm-dd")
Case vbBoolean: Debug.Print c.Address, "logical: " & v
Case vbError: Debug.Print c.Address, "error: " & c.Text
End Select
End Sub
整数が Double になる理由と、通貨の表示形式がデータを丸める理由
二つの驚きは、同じ事実から生まれます。Excel はすべての数値を Double として保存していて、.Value はそれをセルの表示形式に合わせて着飾らせて返すのです。
整数は Double です。 42 が入ったセルは vbLong ではなく vbDouble を返します。If VarType(c.Value) = vbLong と判定するコードは、どのセルにも一致しません。「整数かどうか」を尋ねたいなら、まずタグを、次に値を、二段階で確かめてください。VBA の And は両辺を評価しますし、Int は文字列に対して失敗するからです。If VarType(v) = vbDouble Then isWhole = (v = Int(v)) のように書きます。
表示形式がタグを変えます。 セルに通貨の表示形式が設定されていれば .Value は Currency を返し、日付の表示形式なら Date を返します。同僚が列の表示形式を変えるだけで、値には一切触れていないのに、あなたのコードが受け取るものが変わるのです。しかも Currency は小数点以下 4 桁までしか保持しません。日本では通貨の表示形式といえば小数のない ¥ 表示が普通なので、見た目は丸まっていても値は保たれていると思いがちですが、為替レート 1.234567 のセルにうっかり通貨や会計の表示形式を適用すると、VBA からは 1.2346 として読み取られます。
.Value2 はこの着飾りをしません。数値も日付も通貨も、すべて完全な精度の Double で返します。計算用のコードでは .Value2 を読んでください。
Debug.Print TypeName(Range("B2").Value) ' Currency (B2 に通貨の表示形式を設定)
Debug.Print TypeName(Range("B2").Value2) ' Double
同じ違いの日付側については Value2 のガイド で扱っています。
VarType はオブジェクトを通り抜け、TypeName はオブジェクトの名前を返す
値ではなく Range そのものを渡すと、二つの関数の答えは食い違います。
Debug.Print TypeName(Range("A1")) ' Range
Debug.Print VarType(Range("A1")) ' A1 が数値なら 5。vbObject ではない
VarType は、既定のプロパティを持つオブジェクトを通り抜けて、そのプロパティの型を報告します。Range の既定のプロパティは値なので、VarType(Range("A1")) はセルの中身を表し、vbObject(9)を返すのは既定のプロパティを持たないオブジェクトだけです。一方 TypeName はオブジェクトそのものを報告します。
ですからルールは単純です。オブジェクトが何かを尋ねるには TypeName(または TypeOf)を、値が何かを尋ねるには VarType を使う。
単一セルと複数セルで変わる配列の落とし穴
範囲を Variant に読み込むのはデータを処理する速い方法ですが、落とし穴が隠れています。
Dim data As Variant
data = Range("A2:A" & lastRow).Value
Debug.Print data(1, 1) ' lastRow = 2 のとき実行時エラー 13
範囲が複数のセルなら、data は二次元配列です。ところが lastRow が 2 で範囲が単一のセルだと、data はそのセルの値そのものになり、添字でアクセスすると Type mismatch(「型が一致しません。」)で失敗します。レポートは何か月も動いたあと、データが一行しかない日に止まります。
IsArray で確認し、単一の値は自分で配列に包んでください。
If Not IsArray(data) Then
Dim one(1 To 1, 1 To 1) As Variant
one(1, 1) = data
data = one
End If
IsArray(v) は (VarType(v) And vbArray) <> 0 と同じ判定です。範囲を配列に読み込む方法は 配列のガイド で扱っています。
ユーザーが選択しているものを確認する
TypeName のもっとも多い実用的な使い道は、選択範囲を対象にするマクロの冒頭に置くガードです。ユーザーはセルではなく、グラフや図形、画像をクリックしているかもしれません。
Sub FormatSelectedCells()
If TypeName(Selection) <> "Range" Then
MsgBox "Select some cells first."
Exit Sub
End If
Selection.NumberFormat = "#,##0.00"
End Sub
ガードがないと、グラフが選択されているときに Selection.NumberFormat がエラー 438(Object doesn't support this property or method、日本語版 Excel では「オブジェクトは、このプロパティまたはメソッドをサポートしていません。」)を発生させます。If Not TypeOf Selection Is Range Then も同じ確認をしますが、こちらは Range のつづり間違いをコンパイラーが見つけてくれます。文字列の "Range" のつづり間違いは見つけられません。判定のロジックには TypeOf を、名前を表示したりログに残したりしたいときには TypeName を使いましょう。その他の点は Selection のガイド で扱っています。
判断の分かれ目:境界で尋ね、それ以外では宣言する
VarType と TypeName は国境の検問所です。値が外からコードに入ってくる場所で使ってください。セルの値、ユーザーの選択範囲、Variant 型の引数、Collection の要素、Application.Match の結果などです。自分のコードの内側では Long、String、Double、Range を宣言し、確認はコンパイラーに任せます。
マクロの途中のあちこちに VarType の確認が散らばっているなら、本当の直し方は、各値を一度だけ読み、境界で一度だけタグを確認し、そこで宣言済みの変数に変換することです。入口にひとつ置いた Select Case VarType のほうが、奥のほうに散らばった十数個の If TypeName よりも明快で高速です。
ExcelMaster の活用
型にまつわる驚きは、コードではなくデータから来ます。通貨の表示形式に変えられた列、#N/A を返す検索、一行だけを残すフィルターなどです。
ExcelMaster はコードを書く前に、ブックの実際のセル、表示形式、エラーを読み取ります。そのため、マクロは一行しかないケースやエラーの行も含めて、シートに実際に入っている型を正しく扱えます。
よくある質問
VBA の VarType と TypeName の違いは何ですか?
VarType は型を数値で返します。たとえば Double なら 5、String なら 8 です。TypeName は型を単語で返します。たとえば "Double" や "Range" です。オブジェクトに対しては、TypeName はオブジェクトの名前を返し、VarType は既定のプロパティの型を報告します。
VBA でセルのデータ型を調べるには?
TypeName(Range("A1").Value) または VarType(Range("A1").Value) を使います。数値なら Double、文字列なら String、日付の表示形式の数値なら Date、通貨の表示形式の数値なら Currency、エラーなら Error、手つかずのセルなら Empty が返ります。
整数なのに VarType が Double を返すのはなぜですか?
Excel はすべての数値を Double として保存しているので、42 が入ったセルは vbDouble を返します。整数かどうかを調べるには、値が数値であることを確認したあとで v = Int(v) を判定してください。
VBA で選択範囲がセル範囲かどうかを判定するには?
If TypeName(Selection) = "Range" Then または If TypeOf Selection Is Range Then を使います。グラフや図形が選択されている場合、TypeName は代わりにそのオブジェクト名を返します。
VarType の 8204 は何を意味しますか?
8204 は vbArray + vbVariant(8192 + 12)で、Variant の配列を表します。複数セルの範囲の値を読むと、これが返ってきます。
検証環境
検証環境: Excel 365 (Windows 11)、VBA 7.1 — 最終確認 2026-10-04。
関連ガイド: VBA IsEmpty · VBA IsNull · VBA Data Types · VBA Value2 · VBA Array · VBA Selection · VBA Select Case · VBA IsNumeric
