以下是 .js
檔案與 .ts
檔案中檢查運作方式的一些顯著差異。
根據類別主體中的指派推論屬性
ES2015 沒有宣告類別屬性的方法。屬性會動態指派,就像物件文字一樣。
在 .js
檔案中,編譯器會根據類別主體內的屬性指派推論屬性。屬性的型別是建構函式中提供的型別,除非建構函式中未定義,或建構函式中的型別未定義或為 null。如果是這種情況,型別會是這些指派中所有右手邊值的型別聯集。建構函式中定義的屬性總是假設存在,而僅在方法、getter 或 setter 中定義的屬性則被視為選用。
jsTry
classC {constructor() {this.constructorOnly = 0;this.constructorUnknown =undefined ;}method () {this.Type 'boolean' is not assignable to type 'number'.2322Type 'boolean' is not assignable to type 'number'.constructorOnly = false;this.constructorUnknown = "plunkbat"; // ok, constructorUnknown is string | undefinedthis.methodOnly = "ok"; // ok, but methodOnly could also be undefined}method2 () {this.methodOnly = true; // also, ok, methodOnly's type is string | boolean | undefined}}
如果從未在類別主體中設定屬性,則它們會被視為未知。如果您的類別有僅供讀取的屬性,請在建構函式中新增並註解一個宣告,並使用 JSDoc 指定型別。如果稍後會初始化,您甚至不必提供值
jsTry
classC {constructor() {/** @type {number | undefined} */this.prop =undefined ;/** @type {number | undefined} */this.count ;}}letc = newC ();c .prop = 0; // OKType 'string' is not assignable to type 'number'.2322Type 'string' is not assignable to type 'number'.c .count = "string";
建構函式等同於類別
在 ES2015 之前,JavaScript 使用建構函數而非類別。編譯器支援此模式,並將建構函數視為等同於 ES2015 類別。上述屬性推論規則的運作方式完全相同。
jsTry
functionC () {this.constructorOnly = 0;this.constructorUnknown =undefined ;}C .prototype .method = function () {this.Type 'boolean' is not assignable to type 'number'.2322Type 'boolean' is not assignable to type 'number'.constructorOnly = false;this.constructorUnknown = "plunkbat"; // OK, the type is string | undefined};
支援 CommonJS 模組
在 .js
檔案中,TypeScript 了解 CommonJS 模組格式。指派給 exports
和 module.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
檔案中的命名空間。這可用於巢狀類別,例如
jsTry
classC {}C .D = class {};
而且,對於 ES2015 之前的程式碼,它可用於模擬靜態方法
jsTry
functionOuter () {this.y = 2;}Outer .Inner = function () {this.yy = 2;};Outer .Inner ();
它也可被用於建立簡單的命名空間
jsTry
varns = {};ns .C = class {};ns .func = function () {};ns ;
其他變體也允許
jsTry
// IIFEvarns = (function (n ) {returnn || {};})();ns .CONST = 1;// defaulting to globalvarassign =assign ||function () {// code goes here};assign .extra = 1;
物件文字是開放式的
在 .ts
檔案中,初始化變數宣告的物件文字會將其型別提供給宣告。無法新增未在原始文字中指定的任何新成員。此規則在 .js
檔案中放寬;物件文字具有開放式型別(索引特徵),允許新增和查詢未在原始文字中定義的屬性。例如
jsTry
varobj = {a : 1 };obj .b = 2; // Allowed
物件文字的行為就像它們具有索引特徵 [x:string]: any
,允許將它們視為開放式對應,而不是封閉式物件。
與其他特殊 JS 檢查行為一樣,此行為可透過為變數指定 JSDoc 型別來變更。例如
jsTry
/** @type {{a: number}} */varobj = {a : 1 };Property 'b' does not exist on type '{ a: number; }'.2339Property 'b' does not exist on type '{ a: number; }'.obj .= 2; b
null、undefined 和空的陣列初始化項的類型為 any 或 any[]
初始化為 null 或 undefined 的任何變數、參數或屬性的類型為 any,即使已啟用嚴格的 null 檢查。初始化為 [] 的任何變數、參數或屬性的類型為 any[],即使已啟用嚴格的 null 檢查。唯一的例外是具有如上所述多個初始化項的屬性。
jsTry
functionFoo (i = null) {if (!i )i = 1;varj =undefined ;j = 2;this.l = [];}varfoo = newFoo ();foo .l .push (foo .i );foo .l .push ("end");
函數參數預設為選用
由於在 ES2015 之前的 JavaScript 中沒有辦法指定參數的選用性,因此 .js
檔案中的所有函數參數都被視為選用。允許呼叫的參數少於宣告的參數數量。
請注意,呼叫具有過多參數的函式會造成錯誤。
例如
jsTry
functionbar (a ,b ) {console .log (a + " " +b );}bar (1); // OK, second argument considered optionalbar (1, 2);Expected 0-2 arguments, but got 3.2554Expected 0-2 arguments, but got 3.bar (1, 2,3 ); // Error, too many arguments
JSDoc 註解的函式會排除在此規則之外。使用 JSDoc 選擇性參數語法 ([
]
) 來表達選擇性。例如
jsTry
/*** @param {string} [somebody] - Somebody's name.*/functionsayHello (somebody ) {if (!somebody ) {somebody = "John Doe";}console .log ("Hello " +somebody );}sayHello ();
從使用 arguments
推斷出的 Var-args 參數宣告
函式主體具有對 arguments
參照的參照,會被隱含地視為具有 var-arg 參數 (即 (...arg: any[]) => any
)。使用 JSDoc var-arg 語法來指定參數的類型。
jsTry
/** @param {...number} args */functionsum (/* numbers */) {vartotal = 0;for (vari = 0;i <arguments .length ;i ++) {total +=arguments [i ];}returntotal ;}
未指定的類型參數預設為 any
由於 JavaScript 中沒有指定泛型類型參數的自然語法,因此未指定的類型參數預設為 any
。
在 extends 子句中
例如,React.Component
定義為具有兩個類型參數,Props
和 State
。在 .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
jsTry
/** @type{Array} */varx = [];x .push (1); // OKx .push ("string"); // OK, x is of type Array<any>/** @type{Array.<number>} */vary = [];y .push (1); // OKy .push ("string"); // Error, string is not assignable to number
在函式呼叫中
呼叫泛型函式會使用參數來推斷類型參數。有時此程序無法推斷任何類型,主要是因為缺乏推斷來源;在這些情況下,類型參數將預設為 any
。例如
js
var p = new Promise((resolve, reject) => {reject();});p; // Promise<any>;
若要了解 JSDoc 中所有可用的功能,請參閱 參考文件。