目錄
- 一.基本資料型別的兼容性
- 二.介面兼容性
- 三.函式的兼容性
- 四.類的兼容性
- 類的私有成員和受保護成員
- 五.泛型的兼容性
- 六.列舉的兼容性
- 標稱型別簡短介紹
TS 是結構型別系統(structural type system),基于結構/形狀檢查型別,而非型別的名字,
TS 中的兼容性,主要看結構是否兼容,(核心是考慮安全性),結構化的型別系統(又稱鴨子型別檢查),如兩個型別名字不一樣但是無法區分
型別兼容性是基于結構子型別的, 結構型別是一種只使用其成員來描述型別的方式,
如果
x要兼容y,那么y至少具有與x相同的屬性,
這里要檢查y是否能賦值給x,編譯器檢查x中的每個屬性,看是否能在y中也找到對應屬性,
X 兼容 Y:X(目標型別)= Y(源型別)
簡單一句話概括兼容性: 重新賦值不報錯(型別自動轉化)
一.基本資料型別的兼容性
let temp: string | number;
let num!: number;
temp = num;
let obj: {
toString(): string;
};
let str: string = "yya";
obj = str; // 字串中具備toString()方法,所以可以進行兼容
obj.toString(); // 安全, 保證使用的時候不會發生例外
二.介面兼容性
介面的兼容性,只要滿足介面中所需要的型別即可!(保證你要的,我都有,就行,多了也沒關系)
interface IAnimal {
name: string;
age: number;
}
interface IPerson {
name: string;
age: number;
address: string;
}
let animal: IAnimal;
let person: IPerson = {
name: "yya",
age: 18,
address: "beijing",
};
type T2 = IPerson extends IAnimal ? true : false; // true
animal = person; // 子類賦予給父類 兼容
三.函式的兼容性
函式的兼容性主要是比較引數和回傳值
引數:賦值函式的引數要少于等于被賦值的函式:也就是說,對應函式的引數來講,少的引數可以賦予給多的,因為內部實作傳了多個可以少用或不用(忽略額外的引數在 JavaScript 里是很常見的)
sum2的每個引數必須能在sum1里找到對應型別的引數, 注意的是引數的名字相同與否無所謂,只看它們的型別, sum2的每個引數在sum1中都能找到對應的引數,所以允許賦值,
let sum1 = (a: string, b: string) => a + b;
let sum2 = (a: string) => a;
sum1 = sum2;
舉例: Array#forEach給回呼函式傳 3 個引數:item,index 和 array, 盡管如此,傳入一個只使用第一個引數的回呼函式也是可以的
type Func<T> = (item: T, index: number, array: any[]) => void;
function forEach<T>(arr: T[], cb: Func<T>) {
for (let i = 0; i < arr.length; i++) {
cb(arr[i], i, arr);
}
}
forEach([1, 2, 3], (item) => {
console.log(item);
});
回傳值:
type sum1 = () => string | number;
type sum2 = () => string;
let fn1: sum1;
let fn2!: sum2;
fn1 = fn2;
四.類的兼容性
類與物件字面量和介面差不多,但有一點不同:類有靜態部分和實體部分的型別, 比較兩個型別別的物件時,只有實體的成員會被比較, 靜態成員和建構式不在比較的范圍內,
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
類的私有成員和受保護成員
只要有 private 或者 protected 關鍵字會影響兼容性, 當檢查類實體的兼容時,如果目標型別包含一個 private 私有成員,那么源型別必須包含來自同一個類的這個私有成員, 這條規則也適用于包含 protected 受保護成員實體的型別檢查, 允許子類賦值給父類,但是不能賦值給其它有同樣型別的類,
class A {
private name!: string;
age!: number;
}
class B {
private name!: string;
age!: number;
}
// let a: A = new B(); // error
class Parent {
protected name: string = "zf";
age: number = 11;
}
class Child extends Parent {}
let child: Parent = new Child(); // ok
五.泛型的兼容性
泛型比較的是最終的結果 比較的不是泛型傳遞的引數
例一:
interface Empty<T> {}
let x: Empty<number>;
let y!: Empty<string>;
type xx = Empty<number> extends Empty<string> ? true : false; // true
x = y; // OK 因為 y 匹配 x 的結構
在例一中,x 和 y 是兼容的,因為它們的結構使用型別引數時并沒有什么不同, 把這個例子改變一下,增加一個成員,就能看出是如何作業的了:
例二:
interface NotEmpty<T> {
data: T;
}
let x: NotEmpty<number>;
let y: NotEmpty<string>;
type xx = NotEmpty<number> extends NotEmpty<string> ? true : false; // false
x = y; // Error, 不兼容
對于沒指定泛型型別的泛型引數時,會把所有泛型引數當成 any 比較, 然后用結果型別進行比較,就像例一:
let identity = function <T>(x: T): T {};
let reverse = function <U>(y: U): U {};
identity = reverse; // OK, (x: any) => any 匹配 (y: any) => any
六.列舉的兼容性
列舉型別與數字型別兼容,并且數字型別與列舉型別兼容
enum Status {
Pending,
Resolved,
Rejected,
}
let current = Status.Pending;
let num = 0;
current = num;
num = current;
不同列舉型別之間是不兼容的,
enum Status {
Pending,
Resolved,
Rejected,
}
enum Color {
Red,
Blue,
Green,
}
let current = Status.Pending;
let color = Color.Red;
current = color; // 不能將型別“Color.Red”分配給型別“Status”
標稱型別簡短介紹
型別分為兩種 結構化型別(structural type system) 、標稱型別(nominal type system)
標稱型別: 雖然 BTC,USDT 都是 number 型別,但還是想要用不同的型別表示,且不能互換,資料的值本身沒什么區別,安上不同名字就是不同型別,也就是說,標稱型別系統中,兩個變數是否型別兼容(可以交換賦值)取決于這兩個變數顯式宣告的型別名字是否相同,
class AddType<S> {
private _type!: S;
}
type NewType<T, S extends string> = T & AddType<S>;
type BTC = NewType<number, "btc">; // number + BTC
type USDT = NewType<number, "usdt">; // number + USDT
let btc = 100 as BTC;
let usdt = 100 as USDT;
function getCount(count: USDT) {
return count;
}
getCount(usdt);
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/547539.html
標籤:其他
上一篇:前端設計模式——過濾器模式
下一篇:在京東如何做好前端系統的可觀測性
