typescript中高級類型之交叉類型與聯合類型


交叉類型

交叉類型的表示方法為 Type1 & Type2,結果是取這兩個類型的並集。這里是官網的例子,做了注釋:

// 定義函數 extend,用來合並對象
function extend<T, U>(first: T, second: U): T & U {
    // result 是要返回結果,類型斷言為 T & U
    let result = {} as T & U

    // 遍歷 first,結果存入 result
    for(let id in first){
        // 不能將類型“T”分配給類型“T & U”,所以需使用斷言
        result[id] = first[id] as any
    }

    // 遍歷 second,結果存入 result
    for(let id in second){
        if(!result.hasOwnProperty(id)){
            // 不能將類型“U”分配給類型“T & U”,同樣需要斷言
            result[id] = second[id] as any
        }
    }

    // 返回結果,類型是 T & U
    return result
}

// 定義 Person 類,有 name 實例屬性,類型為 string
class Person{
    constructor(public name: string){}
}

// 定義接口,要求有 log() 函數
interface Loggable{
    log(): void
}

// 定義 ConsoleLogger 類,它實現了接口 Loggable,有實例方法 log()
class ConsoleLogger implements Loggable{
    log(){

    }
}

// 使用 extend 方法合並兩個類的實例,返回的是交叉類型,所以可以訪問 name 和 log()
let jim = extend(new Person('Jim'), new ConsoleLogger())
let n = jim.name
jim.log()

例子中的結果可以看到,交叉類型取的是並集,擁有兩個類型成員的所有屬性。

 

聯合類型

聯合類型的表示方法為 Type1 | Type2,結果是這兩個類型中的一個。還是以官網例子做解釋:

function PadLeft(value: string, padding: any){
    // 如果是 number 類型,則在 value 前填充對用空格
    if(typeof padding === 'number'){
        return Array(padding + 1).join(' ') + value
    }
    // 如果是 string 類型,則直接拼接 value 和 padding
    if(typeof padding === 'string'){
        return padding + value
    }

    // 如果不是 string 和 number,拋出錯誤
    throw new Error(`Expected string or number, got '${padding}'.`)
}

PadLeft("hello world", 4) // '    hello world'

上述代碼可以通過編譯,能正常運行,但是有一個問題,就是 padding 的類型,當 padding 傳入的既不是 number 也不是 string 時,雖然運行結果會拋出錯誤,但是在編譯階段不會提示問題:

padLeft("Hello world", true); // 編譯階段通過,運行時報錯

要在編譯階段就可以知道問題,可以使用聯合類型來替代 any 類型:

function PadLeft(value: string, padding: string | number){
    // ...
}

PadLeft("hello world", true) // error,類型“true”的參數不能賦給類型“string | number”的參數。

聯合類型表示一個值可以是幾種類型之一。 我們用豎線( |)分隔每個類型,所以 number | string | boolean 表示一個值可以是 number, string,或 boolean

 

需要注意的是,訪問聯合類型的屬性時,只能訪問此聯合類型的所有類型里共有的屬性:

let a: string | number

a.length // 類型“string | number”上不存在屬性“length”。類型“number”上不存在屬性“length”。

length 不存在於 number,所以編譯不通過。可以看出這跟交叉類型不一樣,交叉類型是可以訪問所有成員的屬性。

 

總結

交叉類型是多個類型合並為一個類型,可以訪問所有類型的屬性;聯合類型是多個類型中的某一個,只能訪問所有類型的共有屬性。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM