TypeScript——JavaScript文件類型檢查(一)

TypeScript 2.3以后的版本支持使用--checkJs對(duì).js文件進(jìn)行類型檢查和錯(cuò)誤提示。

你可以通過(guò)添加// @ts-nocheck注釋來(lái)忽略類型檢查;相反,你可以通過(guò)去掉--checkJs設(shè)置并添加一個(gè)// @ts-check注釋來(lái)選則檢查某些.js文件。 你還可以使用// @ts-ignore來(lái)忽略本行的錯(cuò)誤。 如果你使用了tsconfig.json,JS檢查將遵照一些嚴(yán)格檢查標(biāo)記,如noImplicitAny,strictNullChecks等。 但因?yàn)镴S檢查是相對(duì)寬松的,在使用嚴(yán)格標(biāo)記時(shí)可能會(huì)有些出乎意料的情況。

對(duì)比.js文件和.ts文件在類型檢查上的差異,有如下幾點(diǎn)需要注意:

用JSDoc類型表示類型信息

.js文件里,類型可以和在.ts文件里一樣被推斷出來(lái)。 同樣地,當(dāng)類型不能被推斷時(shí),它們可以通過(guò)JSDoc來(lái)指定,就好比在.ts文件里那樣。 如同TypeScript,--noImplicitAny會(huì)在編譯器無(wú)法推斷類型的位置報(bào)錯(cuò)。 (除了對(duì)象字面量的情況;后面會(huì)詳細(xì)介紹)

JSDoc注解修飾的聲明會(huì)被設(shè)置為這個(gè)聲明的類型。比如:

/** @type {number} */

var x;

x = 0;? ? ? // OK

x = false;? // Error: boolean is not assignable to number

你可以在這里找到所有JSDoc支持的模式,JSDoc文檔。

屬性的推斷來(lái)自于類內(nèi)的賦值語(yǔ)句

ES2015沒(méi)提供聲明類屬性的方法。屬性是動(dòng)態(tài)賦值的,就像對(duì)象字面量一樣。

在.js文件里,編譯器從類內(nèi)部的屬性賦值語(yǔ)句來(lái)推斷屬性類型。 屬性的類型是在構(gòu)造函數(shù)里賦的值的類型,除非它沒(méi)在構(gòu)造函數(shù)里定義或者在構(gòu)造函數(shù)里是undefined或null。 若是這種情況,類型將會(huì)是所有賦的值的類型的聯(lián)合類型。 在構(gòu)造函數(shù)里定義的屬性會(huì)被認(rèn)為是一直存在的,然而那些在方法,存取器里定義的屬性被當(dāng)成可選的。

class C {

? ? constructor() {

? ? ? ? this.constructorOnly = 0

? ? ? ? this.constructorUnknown = undefined

? ? }

? ? method() {

? ? ? ? this.constructorOnly = false // error, constructorOnly is a number

? ? ? ? this.constructorUnknown = "plunkbat" // ok, constructorUnknown is string | undefined

? ? ? ? this.methodOnly = 'ok'? // ok, but y could also be undefined

? ? }

? ? method2() {

? ? ? ? this.methodOnly = true? // also, ok, y's type is string | boolean | undefined

? ? }

}

如果一個(gè)屬性從沒(méi)在類內(nèi)設(shè)置過(guò),它們會(huì)被當(dāng)成未知的。

如果類的屬性只是讀取用的,那么就在構(gòu)造函數(shù)里用JSDoc聲明它的類型。 如果它稍后會(huì)被初始化,你甚至都不需要在構(gòu)造函數(shù)里給它賦值:

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";? // Error: string is not assignable to number|undefined

構(gòu)造函數(shù)等同于類

ES2015以前,Javascript使用構(gòu)造函數(shù)代替類。 編譯器支持這種模式并能夠?qū)?gòu)造函數(shù)識(shí)別為ES2015的類。 屬性類型推斷機(jī)制和上面介紹的一致。

function C() {

? ? this.constructorOnly = 0

? ? this.constructorUnknown = undefined

}

C.prototype.method = function() {

? ? this.constructorOnly = false // error

? ? this.constructorUnknown = "plunkbat" // OK, the type is string | undefined

}

支持CommonJS模塊

在.js文件里,TypeScript能識(shí)別出CommonJS模塊。 對(duì)exports和module.exports的賦值被識(shí)別為導(dǎo)出聲明。 相似地,require函數(shù)調(diào)用被識(shí)別為模塊導(dǎo)入。例如:

// same as `import module "fs"`

const fs = require("fs");

// same as `export function readFile`

module.exports.readFile = function(f) {

? return fs.readFileSync(f);

}

對(duì)JavaScript文件里模塊語(yǔ)法的支持比在TypeScript里寬泛多了。 大部分的賦值和聲明方式都是允許的。

類,函數(shù)和對(duì)象字面量是命名空間

.js文件里的類是命名空間。 它可以用于嵌套類,比如:

class C {

}

C.D = class {

}

ES2015之前的代碼,它可以用來(lái)模擬靜態(tài)方法:

function Outer() {

? this.y = 2

}

Outer.Inner = function() {

? this.yy = 2

}

它還可以用于創(chuàng)建簡(jiǎn)單的命名空間:

var ns = {}

ns.C = class {

}

ns.func = function() {

}

同時(shí)還支持其它的變化:

// 立即調(diào)用的函數(shù)表達(dá)式

var ns = (function (n) {

? return n || {};

})();

ns.CONST = 1

// defaulting to global

var assign = assign || function() {

? // code goes here

}

assign.extra = 1

對(duì)象字面量是開放的

.ts文件里,用對(duì)象字面量初始化一個(gè)變量的同時(shí)也給它聲明了類型。 新的成員不能再被添加到對(duì)象字面量中。 這個(gè)規(guī)則在.js文件里被放寬了;對(duì)象字面量具有開放的類型,允許添加并訪問(wèn)原先沒(méi)有定義的屬性。例如:

var obj = { a: 1 };

obj.b = 2;? // Allowed

對(duì)象字面量的表現(xiàn)就好比具有一個(gè)默認(rèn)的索引簽名[x:string]: any,它們可以被當(dāng)成開放的映射而不是封閉的對(duì)象。

與其它JS檢查行為相似,這種行為可以通過(guò)指定JSDoc類型來(lái)改變,例如:

/** @type {{a: number}} */

var obj = { a: 1 };

obj.b = 2;? // Error, type {a: number} does not have property b

null,undefined,和空數(shù)組的類型是any或any[]

任何用null,undefined初始化的變量,參數(shù)或?qū)傩?,它們的類型是any,就算是在嚴(yán)格null檢查模式下。 任何用[]初始化的變量,參數(shù)或?qū)傩?,它們的類型是any[],就算是在嚴(yán)格null檢查模式下。 唯一的例外是像上面那樣有多個(gè)初始化器的屬性。

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");

函數(shù)參數(shù)是默認(rèn)可選的

由于在ES2015之前無(wú)法指定可選參數(shù),因此.js文件里所有函數(shù)參數(shù)都被當(dāng)做是可選的。 使用比預(yù)期少的參數(shù)調(diào)用函數(shù)是允許的。

需要注意的一點(diǎn)是,使用過(guò)多的參數(shù)調(diào)用函數(shù)會(huì)得到一個(gè)錯(cuò)誤。

例如:

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

使用JSDoc注解的函數(shù)會(huì)被從這條規(guī)則里移除。 使用JSDoc可選參數(shù)語(yǔ)法來(lái)表示可選性。比如:

/**

* @param {string} [somebody] - Somebody's name.

*/

function sayHello(somebody) {

? ? if (!somebody) {

? ? ? ? somebody = 'John Doe';

? ? }

? ? console.log('Hello ' + somebody);

}

sayHello();

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容