類型1 & 類型2 & 類型3
interface CatInterface { run(): void } interface DogInterface { jump(): void } // 交叉類型具備全部類型的特性 let pet: CatInterface & DogInterface = { run() {}, jump() {} }
let a: number | string = 2; a = 'hello'; a = undefined; // 能夠爲其子類型 a = true; // Error: 不能將類型「true」分配給類型「string | number」
// 字符串聯合類型 let x: 'typescript' | 'webpack' | 'nodejs'; x = 'webpack'; x = 'hello'; // Error: 不能將類型「"hello"」分配給類型「"typescript" | "webpack" | "nodejs"」 // 數字聯合類型 let y: 1 | 2 | 3; y = 3; y = 33; // Error: 不能將類型「33」分配給類型「1 | 2 | 3」 let z: 'typescript' | 2; z = 'typescript'; z = 2; z = 1; // Error: 不能將類型「1」分配給類型「"typescript" | 2」
enum Pet { Dog, Cat }; interface DogInterface { run(): void; eat(): void; } interface CatInterface { jump(): void; eat(): void; } class Dog implements DogInterface { run() {}; eat() {}; } class Cat implements CatInterface { jump() {}; eat() {}; } function getPet(pet: Pet) { // let smallPet: Dog | Cat let smallPet = pet === Pet.Dog ? new Dog() : new Cat(); // 類型不肯定時,只能取公有成員 smallPet.eat(); smallPet.run(); // 類型「Dog | Cat」上不存在屬性「run」 smallPet.jump(); // 類型「Dog | Cat」上不存在屬性「jump」 return smallPet; }
// 例如:Shape是多個類型的聯合類型,每一個類型都具備一個公共屬性kind,由此在 switch中創建了不一樣類型的保護區塊 interface Rectangle { kind: 'rectangle'; width: number; height: number; } interface Square { kind: 'square'; size: number; } type Shape = Rectangle | Square; function area(s: Shape) { switch(s.kind) { case 'rectangle': return s.width * s.height; case 'square': return s.size * s.size; } }
若是又添加了一個聯合類型,可是又沒有在 area 函數中設定類型保護區塊,會發生什麼呢?node
interface Rectangle { kind: 'rectangle'; width: number; height: number; } interface Square { kind: 'square'; size: number; } // 添加新的聯合類型 interface Circle { kind: 'circle'; r: number; } type Shape = Rectangle | Square | Circle; function area(s: Shape) { switch(s.kind) { case 'rectangle': return s.width * s.height; case 'square': return s.size * s.size; } } console.log(area({ kind: 'circle', r: 1 })); // undefined
執行程序打印出了一個結果 undefined,因爲上例中並無在 area 方法中爲 Circle 指定計算面積的方法,理論上應該提示錯誤,而不是直接返回 undefined。webpack
爲了讓編譯器正確的提示錯誤,有兩種可選方法:web
(1)、爲 area 方法指定返回值類型typescript
function area(s: Shape): number { switch(s.kind) { case 'rectangle': return s.width * s.height; case 'square': return s.size * s.size; } }
(2)、利用never類型數組
// 給定一個 default 分支,經過判斷 s 是否是 never 類型來提示錯誤。 // 若是是 never 類型,則能夠在前面的分支中找到對應的執行代碼; // 若是不是 never 類型,則說明前面的代碼有遺漏,須要補全 function area(s: Shape): number { switch(s.kind) { case 'rectangle': return s.width * s.height; case 'square': return s.size * s.size; default: return ((e: never) => { throw new Error(e) })(s); // 類型「Circle」的參數不能賦給類型「never」的參數 } }
經過錯誤提示補全代碼函數
function area(s: Shape): number { switch(s.kind) { case 'rectangle': return s.width * s.height; case 'square': return s.size * s.size; case 'circle': return Math.PI * s.r ** 2 default: return ((e: never) => { throw new Error(e) })(s); } } console.log(area({ kind: 'circle', r: 1 })); // 3.141592653589793
三、索引類型spa
使用索引類型,編譯器就可以檢查使用了動態屬性名的代碼。例如:從js對象中選取屬性的子集,而後創建一個集合code
let obj = { a: 1, b: 2, c: 3 } function getValues(obj: any, keys: string[]) { return keys.map(key => obj[key]) } // obj 中存在的屬性 console.log(getValues(obj, ['a', 'b'])); // [ 1, 2 ] // obj 中不存的屬性,返回 undefined,而沒有提示報錯 console.log(getValues(obj, ['e', 'f'])); // [ undefined, undefined ]
索引類型能夠用來解決上例中的問題,在認識索引類型以前須要先了解幾個概念:對象
(1)、索引類型查詢操做符 keyof Tblog
對於任何類型T,keyof T 的結果是 類型T的全部公共屬性的字面量的聯合類型
interface Person { name: string; gender: string; age: number; } let personProps: keyof Person; // 'name' | 'gender' | 'age' console.log(personProps)
(2)、索引訪問操做符 T[K]
interface Person { name: string; gender: string; age: number; } let n: Person['name']; // n 的類型是 string let a: Person['age']; // a 的類型是 number
// 一、用T來約束obj // 二、用K來約束keys數組 // 三、給K增長一個類型約束,讓它繼承obj的全部屬性的聯合類型 // 四、函數的返回值是一個數組,數組的元素的類型就是屬性K對應的類型 let obj = { a: 1, b: 2, c: 3 } function getValues<T, K extends keyof T>(obj: T, keys: K[]): T[K][] { return keys.map(key => obj[key]) } // obj 中存在的屬性 console.log(getValues(obj, ['a', 'b'])); // [ 1, 2 ] console.log(getValues(obj, ['e', 'f'])); // Error:不能將類型「string」分配給類型「"a" | "b" | "c"」
四、映射類型
interface Obj { a: string; b: number; c: boolean; }
4-一、同態
同態的意思是:只會做用於舊類型的屬性,而不會引入新的屬性
(1)、Readonly<T> 將舊類型中的每個成員都變成只讀
type ReadonlyObj = Readonly<Obj>;
(2)、Partial<T> 把舊類型中的每個成員都變成可選的
type PartialObj = Partial<Obj>;
(3)、Pick<T, key1 | key2 | keyn> 能夠抽取舊類型中的一些子集
接受兩個參數:第一個是要抽取的對象,第二個是要抽取的屬性的key
type PickObj = Pick<Obj, 'a' | 'c'>;
4-二、非同態,會建立一些新的屬性
(1)、Record<key1 | key2 | keyn, T>
接受兩個參數:第一個參數是一些預約義的新的屬性,第二個參數是一個已知的對象
type RecordObj = Record<'x' | 'y', Obj>;