TypeScript 型別相容

admin發表於2019-05-18

TypeScript型別相容性是基於結構子型別的;結構型別只使用其成員來描述型別。

程式碼例項:

[typescript] 純文字檢視 複製程式碼
interface Antzone {
  webName: string;
}
 
class Antzone {
  webName: string;
}
 
let ant: Antzone;
ant = new Antzone();

程式碼賦值成立;如果是在C#等典型的面嚮物件語言中,程式碼不可能正確。

如果S型別資料要賦值給T型別成功,那麼S型別資料相對於T型別而言,不能具有額外的屬性,同時T中的每個屬性都能在S中找到對應的屬性。程式碼例項如下:

[typescript] 純文字檢視 複製程式碼
interface Antzone {
  webName: string;
  age:number
}
 
let ant: Antzone={
  webName:"螞蟻部落",
  age:4
}

上面程式碼賦值成功,首先物件直接量相較介面而言,沒有額外屬性,同時介面中的每一個屬性都能在物件直接量中找到對應的屬性,且型別匹配。再來看一段程式碼例項:

[typescript] 純文字檢視 複製程式碼
interface Antzone {
  webName: string;
  age:number
}
let ant={
  webName:"螞蟻部落",
  age:4,
  address:"青島市南區"
}
let antzone:Antzone=ant;

很明顯ant具有一個額外的屬性address,但是賦值同樣會成功。官方文件解釋如下:

如果認為S相對於T具有額外屬性,首先S是一個fresh object literal type,並且S中含有T不期望存在的屬性。

fresh object literal type可以直白的理解一個直接的物件直接量,如下程式碼:

[JavaScript] 純文字檢視 複製程式碼
let ant: Antzone={
  webName:"螞蟻部落",
  age:4
}

上面程式碼中物件直接量直接被賦值給目標型別變數,這時候它就是一個fresh型別。

fresh object literal types失去freshness情況如下:

(1).fresh型別資料被widened,結果資料的型別失去freshness。

(2).型別斷言後產生的資料型別型別失去freshness。

關於Widened 型別可以參閱TypeScript Widened 型別一章節。

關於型別斷言可以參閱TypeScript 型別斷言一章節。

再來看前面的程式碼:

[typescript] 純文字檢視 複製程式碼
let ant={
  webName:"螞蟻部落",
  age:4,
  address:"青島市南區"
}

物件直接量首先賦值給ant變數,ant的型別是由直接量推斷而來,是fresh物件直接量型別的Widened形式。

下面再羅列一下常見S可以賦值給T的情況:

(1).S或者T有一個是Any型別:

因為Any型別可以賦值給任意其他型別,也可以被其他任意型別賦值(never型別除外):

[typescript] 純文字檢視 複製程式碼
let any:any=5;
let num:number=any;

關於Any型別可以參閱TypeScript Any 型別一章節。

(2).S是Undefined型別:

在預設情況下,Undefined型別資料可以賦值給其他型別資料,Never型別除外之外:

[typescript] 純文字檢視 複製程式碼
let num:number=undefined;

當指定--strictNullChecks標記,null和undefined只能賦值給void和它們各自。

(3).S是Null型別:

在預設情況下,Undefined型別資料可以賦值給其他型別資料,Never型別除外之外:

[typescript] 純文字檢視 複製程式碼
let num:number=null;

當指定--strictNullChecks標記,null和undefined只能賦值給void和它們各自。

關於Null和Undefined型別可以參閱TypeScript Null和Undefined 型別一章節。

(4).S或者T是列舉型別:

數字和列舉之間是相互相容的,但是不同的列舉之間是不相容的。

[typescript] 純文字檢視 複製程式碼
enum Color {
  blue,
  red,
  yellow
}
let num:number=Color.blue;

列舉成員值可以賦值給數值型別。

[typescript] 純文字檢視 複製程式碼
enum Color {
  blue,
  red,
  yellow
}
let ant:Color=5;

數字可以賦值給列舉型別資料。

[typescript] 純文字檢視 複製程式碼
enum Color {
  blue,
  red,
  yellow
}
Color.blue=1;

不能給列舉成員賦值,因為它們是常數。

(5).如果S是聯合型別,並且每一個型別可以賦值給T型別:

[typescript] 純文字檢視 複製程式碼
let ant:"螞蟻部落"|"青島市南區"="螞蟻部落";
let str:string=ant;

ant是聯合型別資料,並且組成聯合型別的每一個字串字面型別都可以賦值給字串型別變數。

(6).如果S是交叉型別,那麼至少有一個型別可以賦值給T:

[typescript] 純文字檢視 複製程式碼
interface One{
  webName:string;
}
interface Two{
  age:number;
}
 
interface Itest{
  age:number;
}
type ant=One&Two;
 
let antzone:ant={
  webName:"螞蟻部落",
  age:4
}
 
let test:Itest=antzone;

(7).如果T是一個聯合型別,那麼S只要可賦值給組成聯合型別的任意一個型別:

[typescript] 純文字檢視 複製程式碼
type tp=string|number;
let ant:tp="螞蟻部落";

(8).如果是T是交叉型別,那麼S(非fresh type)需要可以賦值給組成交叉型別的每一個型別:

[typescript] 純文字檢視 複製程式碼
interface One{
  webName:string;
}
 
interface Two{
  age:number;
}
 
type ant=One&Two;
 
let antzone:ant={
  webName:"螞蟻部落",
  age:4
}

還有函式、類和列舉的相容,可以參閱後續相關章節,這裡就不再介紹了。

相關文章