今日はなにの日。

気になったこと勉強になったことのメモ。

今日は、TypeScriptでnumberとNumberに違いあるらしいの日。

目次

とある日

プログラミングの勉強のためLeetCodeでコードを記述しててエラーに遭遇しました。

TypeScript初心者の自分にはそのエラーの原因がちょっと複雑だし、解説してる記事とかがないので調べてみた内容をまとめてます。

起きたエラーについて

その際の再現でコードを記述してます。

このコードは17行目がエラーになります。

let a: Number
let b: number

a = 1
b = 1
console.log(a);
console.log(b);

function numberTest(n: number) {
    console.log("number function");
}

function NumberTest(n: Number) {
    console.log("Number function");
}

numberTest(a)
NumberTest(a)

numberTest(b)
NumberTest(b)

エラー内容

TypeScript-hello-world/Number/test.ts:17:12 - error TS2345: Argument of type 'Number' is not assignable to parameter of type 'number'.
  'number' is a primitive, but 'Number' is a wrapper object. Prefer using 'number' when possible. 

17 numberTest(a)
              ~

    at createTSError (C:\Users\index.ts:750:12)    at reportTSError (C:\Users\index.ts:754:19)    at getOutput (C:\Users\index.ts:941:36)    
    at Object.compile (C:\Users\index.ts:1243:30)
    at Module.m._compile (C:\Users\index.ts:1370:30)
    at Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
    at Object.require.extensions.<computed> [as .ts] (C:\Users\index.ts:1374:12)
    at Module.load (internal/modules/cjs/loader.js:950:32)
    at Function.Module._load (internal/modules/cjs/loader.js:790:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:76:12) {
  diagnosticText: "\x1B[96mTypeScript-hello-world/Number/test.ts\x1B[0m:\x1B[93m17\x1B[0m:\x1B[93m12\x1B[0m - \x1B[91merror\x1B[0m\x1B[90m TS2345: \x1B[0mArgument of type 'Number' is not assignable to parameter of type 'number'.\r\n" +
    "  'number' is a primitive, but 'Number' is a wrapper object. Prefer using 'number' when possible.\r\n" +
    '\r\n' +
    '\x1B[7m17\x1B[0m numberTest(a)\r\n' +
    '\x1B[7m  \x1B[0m \x1B[91m           ~\x1B[0m\r\n',
  diagnosticCodes: [ 2345 ]
}

Numberとnumberの違い

上記のコードからもわかるようにTypeScript上ではnumberNumberには明確な違いがありました。

Numberの定義

JavaScriptにはたった1つの数値型しかありません。倍精度の64ビットの数値(Number)です。以下でその限界値と望ましい解決策について説明します。

Number型 - TypeScript Deep Dive 日本語版

VSCodeの機能でNumberにカーソルを合わせると下記の文字が表示されます。(どれが要因ででてるかはわからないです)

interface Number

An object that represents a number of any kind. All JavaScript numbers are 64-bit floating-point numbers.

interface Numberがとても気になりました。

Goだとinterface型を作成できてかなり自由に扱えていました。

調べてもあまり明確にNumberのinterfaceという記述が見つかりませんでしたがおそらくNumberというinterfaceとして定義されていると思われます。

Number Interfaceについて

interfaceなら拡張できると思って下記のコードを記述するとそれらしい記述が表示されました。

Interface Number2{
    
}

表示内容

any
Unknown keyword or identifier. Did you mean 'number'?ts(1435)
Cannot find name 'Number2'. Did you mean 'Number'?ts(2552)
lib.es5.d.ts(605, 13): 'Number' is declared here.
↓翻訳
任意
不明なキーワードまたは識別子です。数字'という意味ですか?ts(1435)
名前 'Number2' が見つかりません。あなたは'Number'を意味しているのですか?
lib.es5.d.ts(605, 13): 'Number' はここで宣言されています。

その場所を見てみた。

確かにinterfaceで定義されている。

interface Number {
    /**
     * Returns a string representation of an object.
     * @param radix Specifies a radix for converting numeric values to strings. This value is only used for numbers.
     */
    toString(radix?: number): string;

    /**
     * Returns a string representing a number in fixed-point notation.
     * @param fractionDigits Number of digits after the decimal point. Must be in the range 0 - 20, inclusive.
     */
    toFixed(fractionDigits?: number): string;

    /**
     * Returns a string containing a number represented in exponential notation.
     * @param fractionDigits Number of digits after the decimal point. Must be in the range 0 - 20, inclusive.
     */
    toExponential(fractionDigits?: number): string;

    /**
     * Returns a string containing a number represented either in exponential or fixed-point notation with a specified number of digits.
     * @param precision Number of significant digits. Must be in the range 1 - 21, inclusive.
     */
    toPrecision(precision?: number): string;

    /** Returns the primitive value of the specified object. */
    valueOf(): number;
}

numberの定義

数値型 (number type)

JavaScriptの数値型は、1や-1などの整数と0.1などの小数を含めた数値の型です。PHPなどの言語では、数値について整数を表す型(int)と小数を表す型(floatやdouble)の2つの型を持ちます。Javaなどの言語では、整数型をさらに32ビットと64ビットに細分化する言語もあります。JavaScriptには、整数と小数を型レベルで区別するものはありません。どちらも数値型で表現します。

数値型 (number type) | TypeScript入門『サバイバルTypeScript』

let b: number = 1;

数値型を定義するときに使用する。

まとめ

調べてみた自分の各要素についてまとめました。

  • numberは数値型で実際の数値に適応する型
  • Numberは interface型でnumberを定義している上位の存在

基本的には、数値型を定義するときはnumberを使う。

numberとNumberの違いについてはTypeScript独特のふるまいな気がするのでまだまだ初心者の自分にはわからないことだらけですが、下記の記事のような違いがある気がしてます。

interfaceとtypeの違い、そして何を使うべきかについて

TypeScriptの入門として優れているとよく聞くTypeScript入門では下記が記載されていました。

よく似た名前の型としてNumber型がありますが、これとnumberは別物なので注意してください。

数値型 (number type) | TypeScript入門『サバイバルTypeScript』

TypeScriptではよくある間違いとして扱われてそうだなと思いました。

特に何も思わず定義してたら実は違って困惑した話です。

TypeScriptも奥が深いですね。