12.typescript筆記_類型兼容

什麼是類型兼容?
當一個類型 Y 可以被賦值給另一個類型 X 時 , 我們就可以說類型 X 兼容 類型 Y
X 兼容 Y : X (目標類型) = Y (源類型)

let a : string = "1";
a = null;//正常這樣書寫會報錯, 那麼可以把ts的配置strictNullChecks 設置爲false即可
//這樣就可以說, 字符型 是兼容 null類型的,也就是說null是字符類型的子類型
//這裏討論類型的兼容性問題, 是因爲ts在某種情況下,允許我們將不同類型的值進行賦值, 雖然
//有一些不可靠性,但是也增加了靈活性

1. 接口的兼容性

interface X{
    a : any ;
    b : any ;
}

interface Y {
    a : any ;
    b : any ;
    c : any ;
}

let x : X = { a : 1 , b : 2 };
let y : Y = { a : 1 , b : 2 , c : 3}
//這裏x可以賦值給y,但是y不能賦值爲x ,那是因爲源類型必須具備目標類型的必要屬性
//接口相互兼容性問題,成員少的可兼容成員多的
x = y;
// y = x;報錯

2… 函數的兼容性
通常發生在兩個函數相互賦值的情況下

2.1 函數作爲參數的情況下

//1)參數個數
let handler1 = (a : number) => {};
hor(handler1);//可以兼容,參數少的兼容參數多的,且源類型具備了目標類型的必要屬性
let handler2 = (a : number , b : number , c : number) => {};
// hor(handler2);//不可兼容,因爲參數比源類型多
//可選參數和剩餘參數
let a1 = (p1 : number , p2 : number) => {};
let a2 = (p1 ? : number , p2 ? : number) => {};
let a3 = (...args : number[]) => {};

//固定參數可以兼容可選參數和剩餘參數
a1 = a2;
a1 = a3;
//可選參數不可兼容固定參數和剩餘參數,但是可以通過配置,讓其兼容;strictFunctionTypes:false
a2 = a1;
a2 = a3;
a3 = a1;
a3 = a2;
//2)參數類型
interface Point3D {
    X : number ;
    y : number ;
    z : number ;
}

interface Point2D {
    X : number ;
    y : number ;
}
let p3d = ( point : Point3D) => {};
let p2d = ( point : Point2D) => {};
//這裏會發現,有違背了之前的定義,應該是參數少的兼容參數多的,但是這裏不一樣,記特殊情況
//當一個函數的參數是一個對象類型時, 參數多的兼容參數少的
p3d = p2d;
//反而參數少的不能兼容參數多的,如果想兼容,可以做ts配置中進行設置,strictFunctionTypes : false
p2d = p3d;
//小結:這種情況叫做函數的參數雙向斜變,可以把一個精確的類型允許賦值給一個不那麼精確的類型,這樣做很方便
//這樣我們可以不用把一個不精確的類型,斷言成一個精確的類型
//3)返回值類型
//目標函數的返回類型,必須和源函數類型的返回類型相同
let f = () => ({name : 'Alice'});
let g = () => ({name : 'Alice' , location : "Beijing"});
f = g;
// g = f;//返回值類型遵循鴨試變形法, 參數少的兼容參數多的
//函數重載兼容,第一行參數是目標類型,以外的都是源類型,源類型的參數必須和目標類型一致
function overload(a:number , b : number) : number;
function overload(a:string , b : string) : string;
function overload(a:any , b : any) : any{};
//枚舉兼容性
enum Fruit {Apple , Bamama};
enum Color { Red , Yellow};
let fruit : Fruit.Apple = 3;
let no : number = Fruit.Apple;
//兩個枚舉之間,是不可兼容的
// let color : Color.Red = Fruit.Apple;
//類兼容性
class A {
    constructor( p : number , q : number) {}
    id : number = 1;
    private a = 1;
}
class B {
    static s = 1;
    constructor(p : number) {}
    id : number = 1;
}
let aa = new A(1,2);
let bb = new B(1);
//類的兼容, 不管構造器的參數,和靜態成員參數, 只要id參數相同, 即可兼容,注意,將私有屬性private去掉即可相互兼容
// aa = bb;
// bb = aa;
//如果類中有private屬性,將不可互相兼容, 只可子類繼承父類後,子類實例化可以兼容父類的實例化
class C extends A {};
let cc = new C(1,2);
cc = aa;
aa = cc;
//泛型的兼容性
  interface Empty<T>{
      value : T
  };
  // let object1 : Empty<string> = {};
  // let object2 : Empty<number> = {};
  //當泛型接口中,沒有參數定義時,是可以相互兼容的
  // object1 = object2;
  //當泛型接口中,有參數定義時,是不可相互兼容的
let log1 = <T>(value : T) : T => {
    return value;
}
let log2 = <U>(y : U) : U =>{
    return y;
}
log1 = log2;
}

總結
口訣:
結構之間的兼容 : 成員少的兼容成員多的:
函數之間的兼容 : 參數多的兼容參數少的

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章