日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
創(chuàng)新互聯(lián)TypeScript教程:TypeScript類型兼容性

TypeScript里的類型兼容性是基于結(jié)構(gòu)子類型的。 結(jié)構(gòu)類型是一種只使用其成員來(lái)描述類型的方式。 它正好與名義(nominal)類型形成對(duì)比。(譯者注:在基于名義類型的類型系統(tǒng)中,數(shù)據(jù)類型的兼容性或等價(jià)性是通過(guò)明確的聲明和/或類型的名稱來(lái)決定的。這與結(jié)構(gòu)性類型系統(tǒng)不同,它是基于類型的組成結(jié)構(gòu),且不要求明確地聲明。) 看下面的例子:

interface Named {
    name: string;
}

class Person {
    name: string;
}

let p: Named;
// OK, because of structural typing
p = new Person();

在使用基于名義類型的語(yǔ)言,比如C#或Java中,這段代碼會(huì)報(bào)錯(cuò),因?yàn)镻erson類沒(méi)有明確說(shuō)明其實(shí)現(xiàn)了Named接口。

TypeScript的結(jié)構(gòu)性子類型是根據(jù)JavaScript代碼的典型寫(xiě)法來(lái)設(shè)計(jì)的。 因?yàn)镴avaScript里廣泛地使用匿名對(duì)象,例如函數(shù)表達(dá)式和對(duì)象字面量,所以使用結(jié)構(gòu)類型系統(tǒng)來(lái)描述這些類型比使用名義類型系統(tǒng)更好。

關(guān)于可靠性的注意事項(xiàng)

TypeScript的類型系統(tǒng)允許某些在編譯階段無(wú)法確認(rèn)其安全性的操作。當(dāng)一個(gè)類型系統(tǒng)具此屬性時(shí),被當(dāng)做是“不可靠”的。TypeScript允許這種不可靠行為的發(fā)生是經(jīng)過(guò)仔細(xì)考慮的。通過(guò)這篇文章,我們會(huì)解釋什么時(shí)候會(huì)發(fā)生這種情況和其有利的一面。

開(kāi)始

TypeScript結(jié)構(gòu)化類型系統(tǒng)的基本規(guī)則是,如果x要兼容y,那么y至少具有與x相同的屬性。比如:

interface Named {
    name: string;
}

let x: Named;
// y's inferred type is { name: string; location: string; }
let y = { name: 'Alice', location: 'Seattle' };
x = y;

這里要檢查y是否能賦值給x,編譯器檢查x中的每個(gè)屬性,看是否能在y中也找到對(duì)應(yīng)屬性。 在這個(gè)例子中,y必須包含名字是namestring類型成員。y滿足條件,因此賦值正確。

檢查函數(shù)參數(shù)時(shí)使用相同的規(guī)則:

function greet(n: Named) {
    alert('Hello, ' + n.name);
}
greet(y); // OK

注意,y有個(gè)額外的location屬性,但這不會(huì)引發(fā)錯(cuò)誤。 只有目標(biāo)類型(這里是 Named)的成員會(huì)被一一檢查是否兼容。

這個(gè)比較過(guò)程是遞歸進(jìn)行的,檢查每個(gè)成員及子成員。

比較兩個(gè)函數(shù)

相對(duì)來(lái)講,在比較原始類型和對(duì)象類型的時(shí)候是比較容易理解的,問(wèn)題是如何判斷兩個(gè)函數(shù)是兼容的。 下面我們從兩個(gè)簡(jiǎn)單的函數(shù)入手,它們僅是參數(shù)列表略有不同:

let x = (a: number) => 0;
let y = (b: number, s: string) => 0;

y = x; // OK
x = y; // Error

要查看x是否能賦值給y,首先看它們的參數(shù)列表。 x的每個(gè)參數(shù)必須能在y里找到對(duì)應(yīng)類型的參數(shù)。 注意的是參數(shù)的名字相同與否無(wú)所謂,只看它們的類型。 這里, x的每個(gè)參數(shù)在y中都能找到對(duì)應(yīng)的參數(shù),所以允許賦值。

第二個(gè)賦值錯(cuò)誤,因?yàn)?code>y有個(gè)必需的第二個(gè)參數(shù),但是x并沒(méi)有,所以不允許賦值。

你可能會(huì)疑惑為什么允許忽略參數(shù),像例子y = x中那樣。 原因是忽略額外的參數(shù)在JavaScript里是很常見(jiàn)的。 例如, Array#forEach給回調(diào)函數(shù)傳3個(gè)參數(shù):數(shù)組元素,索引和整個(gè)數(shù)組。 盡管如此,傳入一個(gè)只使用第一個(gè)參數(shù)的回調(diào)函數(shù)也是很有用的:

let items = [1, 2, 3];

// Don't force these extra arguments
items.forEach((item, index, array) => console.log(item));

// Should be OK!
items.forEach((item) => console.log(item));

下面來(lái)看看如何處理返回值類型,創(chuàng)建兩個(gè)僅是返回值類型不同的函數(shù):

let x = () => ({name: 'Alice'});
let y = () => ({name: 'Alice', location: 'Seattle'});

x = y; // OK
y = x; // Error because x() lacks a location property

類型系統(tǒng)強(qiáng)制源函數(shù)的返回值類型必須是目標(biāo)函數(shù)返回值類型的子類型。

函數(shù)參數(shù)雙向協(xié)變

當(dāng)比較函數(shù)參數(shù)類型時(shí),只有當(dāng)源函數(shù)參數(shù)能夠賦值給目標(biāo)函數(shù)或者反過(guò)來(lái)時(shí)才能賦值成功。 這是不穩(wěn)定的,因?yàn)檎{(diào)用者可能傳入了一個(gè)具有更精確類型信息的函數(shù),但是調(diào)用這個(gè)傳入的函數(shù)的時(shí)候卻使用了不是那么精確的類型信息。 實(shí)際上,這極少會(huì)發(fā)生錯(cuò)誤,并且能夠?qū)崿F(xiàn)很多JavaScript里的常見(jiàn)模式。例如:

enum EventType { Mouse, Keyboard }

interface Event { timestamp: number; }
interface MouseEvent extends Event { x: number; y: number }
interface KeyEvent extends Event { keyCode: number }

function listenEvent(eventType: EventType, handler: (n: Event) => void) {
    /* ... */
}

// Unsound, but useful and common
listenEvent(EventType.Mouse, (e: MouseEvent) => console.log(e.x + ',' + e.y));

// Undesirable alternatives in presence of soundness
listenEvent(EventType.Mouse, (e: Event) => console.log((e).x + ',' + (e).y));
listenEvent(EventType.Mouse, <(e: Event) => void>((e: MouseEvent) => console.log(e.x + ',' + e.y)));

// Still disallowed (clear error). Type safety enforced for wholly incompatible types
listenEvent(EventType.Mouse, (e: number) => console.log(e));

可選參數(shù)及剩余參數(shù)

比較函數(shù)兼容性的時(shí)候,可選參數(shù)與必須參數(shù)是可交換的。 原類型上額外的可選參數(shù)并不會(huì)造成錯(cuò)誤,目標(biāo)類型的可選參數(shù)沒(méi)有對(duì)應(yīng)的參數(shù)也不是錯(cuò)誤。

當(dāng)一個(gè)函數(shù)有剩余參數(shù)時(shí),它被當(dāng)做無(wú)限個(gè)可選參數(shù)。

這對(duì)于類型系統(tǒng)來(lái)說(shuō)是不穩(wěn)定的,但從運(yùn)行時(shí)的角度來(lái)看,可選參數(shù)一般來(lái)說(shuō)是不強(qiáng)制的,因?yàn)閷?duì)于大多數(shù)函數(shù)來(lái)說(shuō)相當(dāng)于傳遞了一些undefinded

有一個(gè)好的例子,常見(jiàn)的函數(shù)接收一個(gè)回調(diào)函數(shù)并用對(duì)于程序員來(lái)說(shuō)是可預(yù)知的參數(shù)但對(duì)類型系統(tǒng)來(lái)說(shuō)是不確定的參數(shù)來(lái)調(diào)用:

function invokeLater(args: any[], callback: (...args: any[]) => void) {
    /* ... Invoke callback with 'args' ... */
}

// Unsound - invokeLater "might" provide any number of arguments
invokeLater([1, 2], (x, y) => console.log(x + ', ' + y));

// Confusing (x and y are actually required) and undiscoverable
invokeLater([1, 2], (x?, y?) => console.log(x + ', ' + y));

函數(shù)重載

對(duì)于有重載的函數(shù),源函數(shù)的每個(gè)重載都要在目標(biāo)函數(shù)上找到對(duì)應(yīng)的函數(shù)簽名。 這確保了目標(biāo)函數(shù)可以在所有源函數(shù)可調(diào)用的地方調(diào)用。

枚舉

枚舉類型與數(shù)字類型兼容,并且數(shù)字類型與枚舉類型兼容。不同枚舉類型之間是不兼容的。比如,

enum Status { Ready, Waiting };
enum Color { Red, Blue, Green };

let status = Status.Ready;
status = Color.Green;  //error

類與對(duì)象字面量和接口差不多,但有一點(diǎn)不同:類有靜態(tài)部分和實(shí)例部分的類型。 比較兩個(gè)類類型的對(duì)象時(shí),只有實(shí)例的成員會(huì)被比較。 靜態(tài)成員和構(gòu)造函數(shù)不在比較的范圍內(nèi)。

class Animal {
    feet: number;
    constructor(name: string, numFeet: number) { }
}

class Size {
    feet: number;
    constructor(numFeet: number) { }
}

let a: Animal;
let s: Size;

a = s;  //OK
s = a;  //OK

類的私有成員

私有成員會(huì)影響兼容性判斷。 當(dāng)類的實(shí)例用來(lái)檢查兼容時(shí),如果它包含一個(gè)私有成員,那么目標(biāo)類型必須包含來(lái)自同一個(gè)類的這個(gè)私有成員。 這允許子類賦值給父類,但是不能賦值給其它有同樣類型的類。

泛型

因?yàn)門(mén)ypeScript是結(jié)構(gòu)性的類型系統(tǒng),類型參數(shù)只影響使用其做為類型一部分的結(jié)果類型。比如,

interface Empty {
}
let x: Empty;
let y: Empty;

x = y;  // okay, y matches structure of x

上面代碼里,xy是兼容的,因?yàn)樗鼈兊慕Y(jié)構(gòu)使用類型參數(shù)時(shí)并沒(méi)有什么不同。 把這個(gè)例子改變一下,增加一個(gè)成員,就能看出是如何工作的了:

interface NotEmpty {
    data: T;
}
let x: NotEmpty;
let y: NotEmpty;

x = y;  // error, x and y are not compatible

在這里,泛型類型在使用時(shí)就好比不是一個(gè)泛型類型。

對(duì)于沒(méi)指定泛型類型的泛型參數(shù)時(shí),會(huì)把所有泛型參數(shù)當(dāng)成any比較。 然后用結(jié)果類型進(jìn)行比較,就像上面第一個(gè)例子。

比如,

let identity = function(x: T): T {
    // ...
}

let reverse = function(y: U): U {
    // ...
}

identity = reverse;  // Okay because (x: any)=>any matches (y: any)=>any

高級(jí)主題

子類型與賦值

目前為止,我們使用了兼容性,它在語(yǔ)言規(guī)范里沒(méi)有定義。 在TypeScript里,有兩種類型的兼容性:子類型與賦值。 它們的不同點(diǎn)在于,賦值擴(kuò)展了子類型兼容,允許給 any賦值或從any取值和允許數(shù)字賦值給枚舉類型或枚舉類型賦值給數(shù)字。

語(yǔ)言里的不同地方分別使用了它們之中的機(jī)制。 實(shí)際上,類型兼容性是由賦值兼容性來(lái)控制的甚至在implementsextends語(yǔ)句里。 更多信息,請(qǐng)參閱 TypeScript語(yǔ)言規(guī)范.


本文題目:創(chuàng)新互聯(lián)TypeScript教程:TypeScript類型兼容性
文章位置:http://m.5511xx.com/article/dpjsspi.html