TS學習筆記(七):類型兼容性

類型兼容性用於肯定一個類型是否能賦值給其餘類型,TypeScript 結構化類型系統的基本規則是,若是 x 要兼容 y,那麼 y 至少具備與 x 相同的屬性。typescript

示例

interface INamed {
  name: string;
}

let x: INamed;
let y = {
  name: 'funlee',
  age: 18
};

x = y;
複製代碼

函數的兼容性

在考慮函數的兼容性的時候,須要考慮一些額外的東西。ide

參數數量

要查看 x 是否能賦值給 y,首先看它們的參數列表,x 的每一個參數必須能在 y 裏找到對應類型的參數,注意的是參數的名字相同與否無所謂,只看它們的類型。函數

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

y = x; // OK
x = y; // Error
複製代碼

返回類型

類型系統強制源函數的返回值類型必須是目標函數返回值類型的子類型。ui

interface Point2D {
  x: number;
  y: number;
}
interface Point3D {
  x: number;
  y: number;
  z: number;
}

let iMakePoint2D = (): Point2D => ({ x: 0, y: 0 });
let iMakePoint3D = (): Point3D => ({ x: 0, y: 0, z: 0 });

iMakePoint2D = iMakePoint3D;
iMakePoint3D = iMakePoint2D; // ERROR: Point2D 不能賦值給 Point3D
複製代碼

可選的和 rest 參數

可選的(預先肯定的)和 Rest 參數(任何數量的參數)都是兼容的:spa

let foo = (x: number, y: number) => {};
let bar = (x?: number, y?: number) => {};
let bas = (...args: number[]) => {};

foo = bar = bas;
bas = bar = foo;
複製代碼

枚舉的兼容性

枚舉與數字類型相互兼容。rest

enum Person {
  name,
  age,
  love
}
let age = Person.age;
let num = 18;

age = num;
num = age;
複製代碼

來自於不一樣枚舉的枚舉變量,被認爲是不兼容的。code

enum Person {
  name,
  age,
  love
}
enum Colors {
  red,
  blue,
  green
}
let age = Person.age;
let blue = Colors.blue;

// age = blue; // error
複製代碼

類的兼容性

僅僅只有實例成員和方法會相比較,構造函數和靜態成員不會被檢查。ip

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

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

let a: Animal;
let s: Size;

a = s; // OK
s = a; // OK
複製代碼

私有的和受保護的成員必須來自於相同的類。string

class Animal {
  protected feet: number;
}
class Cat extends Animal {}

let animal: Animal;
let cat: Cat;

animal = cat; // ok
cat = animal; // ok

class Size {
  protected feet: number;
}

let size: Size;

animal = size; // ERROR
size = animal; // ERROR
複製代碼

泛型的兼容性

TypeScript 類型系統基於變量的結構,僅當類型參數在被一個成員使用時,纔會影響兼容性。以下例子中,T 對兼容性沒有影響:it

interface Empty<T> {}

let x: Empty<number>;
let y: Empty<string>;

x = y; // ok
複製代碼

當 T 被成員使用時,它將在實例化泛型後影響兼容性:

interface Empty<T> {
  data: T;
}

let x: Empty<number>;
let y: Empty<string>;

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`
複製代碼

類中的泛型兼容性與類的兼容性所說起一致:

class List<T> {
  add(val: T) {}
}

class Animal {
  name: string;
}
class Cat extends Animal {
  meow() {
    // ..
  }
}

const animals = new List<Animal>();
animals.add(new Animal()); // ok
animals.add(new Cat()); // ok

const cats = new List<Cat>();
cats.add(new Animal()); // Error
cats.add(new Cat()); // ok
複製代碼
相關文章
相關標籤/搜索