型別檢查 JavaScript 檔案

以下是在 .js 檔案中進行型別檢查與在 .ts 檔案中相比的一些顯著差異。

屬性是從類體中的賦值推斷出來的

ES2015 沒有在類上宣告屬性的方法。屬性是動態分配的,就像物件字面量一樣。

.js 檔案中,編譯器從類體內的屬性賦值中推斷屬性。屬性的型別是在建構函式中給出的型別,除非它沒有在建構函式中定義,或者建構函式中的型別為 undefined 或 null。在這種情況下,型別是這些賦值中所有右側值的型別的並集。建構函式中定義的屬性被假定為始終存在,而僅在方法、getter 或 setter 中定義的屬性則被視為可選的。

js
class C {
constructor() {
this.constructorOnly = 0;
this.constructorUnknown = undefined;
}
method() {
this.constructorOnly = false;
Type 'boolean' is not assignable to type 'number'.2322Type 'boolean' is not assignable to type 'number'.
this.constructorUnknown = "plunkbat"; // ok, constructorUnknown is string | undefined
this.methodOnly = "ok"; // ok, but methodOnly could also be undefined
}
method2() {
this.methodOnly = true; // also, ok, methodOnly's type is string | boolean | undefined
}
}
Try

如果屬性從未在類體中設定,則它們被視為未知(unknown)。如果你的類具有僅被讀取的屬性,請在建構函式中新增並使用 JSDoc 註解宣告以指定型別。如果以後會進行初始化,你甚至不需要為其賦初始值。

js
class C {
constructor() {
/** @type {number | undefined} */
this.prop = undefined;
/** @type {number | undefined} */
this.count;
}
}
 
let c = new C();
c.prop = 0; // OK
c.count = "string";
Type 'string' is not assignable to type 'number'.2322Type 'string' is not assignable to type 'number'.
Try

建構函式等同於類

在 ES2015 之前,JavaScript 使用建構函式而不是類。編譯器支援這種模式,並將構造函數理解為等同於 ES2015 類。上述屬性推斷規則以完全相同的方式工作。

js
function C() {
this.constructorOnly = 0;
this.constructorUnknown = undefined;
}
C.prototype.method = function () {
this.constructorOnly = false;
Type 'boolean' is not assignable to type 'number'.2322Type 'boolean' is not assignable to type 'number'.
this.constructorUnknown = "plunkbat"; // OK, the type is string | undefined
};
Try

支援 CommonJS 模組

.js 檔案中,TypeScript 理解 CommonJS 模組格式。對 exportsmodule.exports 的賦值被識別為匯出宣告。類似地,require 函式呼叫被識別為模組匯入。例如:

js
// same as `import module "fs"`
const fs = require("fs");
// same as `export function readFile`
module.exports.readFile = function (f) {
return fs.readFileSync(f);
};

JavaScript 中的模組支援在語法上比 TypeScript 的模組支援寬容得多。支援大多數賦值和宣告的組合。

類、函式和物件字面量即名稱空間

類在 .js 檔案中是名稱空間。這可以用來巢狀類,例如:

js
class C {}
C.D = class {};
Try

此外,對於 ES2015 之前的程式碼,它可用於模擬靜態方法:

js
function Outer() {
this.y = 2;
}
 
Outer.Inner = function () {
this.yy = 2;
};
 
Outer.Inner();
Try

它還可以用於建立簡單的名稱空間:

js
var ns = {};
ns.C = class {};
ns.func = function () {};
 
ns;
Try

其他變體也是允許的:

js
// IIFE
var ns = (function (n) {
return n || {};
})();
ns.CONST = 1;
 
// defaulting to global
var assign =
assign ||
function () {
// code goes here
};
assign.extra = 1;
Try

物件字面量是開放式的

.ts 檔案中,初始化變數宣告的物件字面量會將型別賦予該宣告。不能新增原始字面量中未指定的成員。此規則在 .js 檔案中放寬了;物件字面量具有開放式型別(索引簽名),允許新增和查詢原始定義中未包含的屬性。例如:

js
var obj = { a: 1 };
obj.b = 2; // Allowed
Try

物件字面量的行為就像它們具有索引簽名 [x:string]: any 一樣,這允許它們被視為開放對映(open maps)而不是封閉物件。

與其他特殊的 JS 檢查行為一樣,此行為可以透過為變數指定 JSDoc 型別來更改。例如:

js
/** @type {{a: number}} */
var obj = { a: 1 };
obj.b = 2;
Property 'b' does not exist on type '{ a: number; }'.2339Property 'b' does not exist on type '{ a: number; }'.
Try

null、undefined 和空陣列初始化程式的型別為 any 或 any[]

任何使用 null 或 undefined 初始化的變數、引數或屬性都將具有型別 any,即使啟用了嚴格空值檢查(strict null checks)。任何使用 [] 初始化的變數、引數或屬性都將具有型別 any[],即使啟用了嚴格空值檢查。唯一的例外是如上所述具有多個初始化程式的屬性。

js
function Foo(i = null) {
if (!i) i = 1;
var j = undefined;
j = 2;
this.l = [];
}
 
var foo = new Foo();
foo.l.push(foo.i);
foo.l.push("end");
Try

函式引數預設是可選的

由於在 ES2015 之前的 JavaScript 中沒有指定引數可選性的方法,因此 .js 檔案中的所有函式引數都被視為可選的。允許以少於宣告引數數量的引數進行呼叫。

需要注意的是,使用過多的引數呼叫函式是一個錯誤。

例如:

js
function bar(a, b) {
console.log(a + " " + b);
}
 
bar(1); // OK, second argument considered optional
bar(1, 2);
bar(1, 2, 3); // Error, too many arguments
Expected 0-2 arguments, but got 3.2554Expected 0-2 arguments, but got 3.
Try

JSDoc 註解函式不在此規則範圍內。使用 JSDoc 可選引數語法 ([ ]) 來表達可選性。例如:

js
/**
* @param {string} [somebody] - Somebody's name.
*/
function sayHello(somebody) {
if (!somebody) {
somebody = "John Doe";
}
console.log("Hello " + somebody);
}
 
sayHello();
Try

可變引數(Var-args)宣告根據 arguments 的使用進行推斷

函式體中引用了 arguments 的函式被隱式視為具有可變引數(即 (...arg: any[]) => any)。使用 JSDoc 可變引數語法指定引數型別。

js
/** @param {...number} args */
function sum(/* numbers */) {
var total = 0;
for (var i = 0; i < arguments.length; i++) {
total += arguments[i];
}
return total;
}
Try

未指定的型別引數預設為 any

由於 JavaScript 中沒有指定泛型型別引數的自然語法,未指定的型別引數預設為 any

在 extends 子句中

例如,React.Component 被定義為具有兩個型別引數 PropsState。在 .js 檔案中,沒有合法的方法在 extends 子句中指定這些引數。預設情況下,型別引數將為 any

js
import { Component } from "react";
class MyComponent extends Component {
render() {
this.props.b; // Allowed, since this.props is of type any
}
}

使用 JSDoc @augments 明確指定型別。例如:

js
import { Component } from "react";
/**
* @augments {Component<{a: number}, State>}
*/
class MyComponent extends Component {
render() {
this.props.b; // Error: b does not exist on {a:number}
}
}

在 JSDoc 引用中

JSDoc 中未指定的型別引數預設為 any。

js
/** @type{Array} */
var x = [];
 
x.push(1); // OK
x.push("string"); // OK, x is of type Array<any>
 
/** @type{Array.<number>} */
var y = [];
 
y.push(1); // OK
y.push("string"); // Error, string is not assignable to number
Try

在函式呼叫中

對泛型函式的呼叫使用引數來推斷型別引數。有時此過程無法推斷出任何型別,主要是由於缺乏推斷源;在這種情況下,型別引數將預設為 any。例如:

js
var p = new Promise((resolve, reject) => {
reject();
});
p; // Promise<any>;

要了解 JSDoc 中可用的所有功能,請參閱 參考文件

TypeScript 文件是一個開源專案。透過提交 Pull Request 幫助我們改進這些頁面

此頁面的貢獻者
HNHarry Nguyen (51)
OTOrta Therox (17)
RCRyan Cavanaugh (3)
NSNathan Shively-Sanders (2)
MHMohamed Hegazy (2)
15+

最後更新:2026 年 3 月 27 日