TypeScript的交叉类型

69 阅读2分钟

交叉类型的含义

  • 即类型的交集

    type A = string & number // string 和 number 的交集其实就是 never
    const a: A = 1
    
  • | 和 & 的对比

    // 例子 1 使用 type 定义不重复 key 的类型
    type 有左手的人 = {
        left: string
    }
    type 有右手的人 = {
        right: string
    }
    // A 的含义是有左手或者有右手或者左右手都有
    type A = 有左手的人 | 有右手的人
    // B 的含义是有左手并且有右手
    type B = 有左手的人 & 有右手的人
    // 先看 A 类型
    const obj1 = {
        left: 'left_a',
        right: 'right_a',
        other: 'other'
    }
    const a1: A = {
        left: 'left_a'
    }
    const a2: A = {
        right: 'right_a'
    }
    const a3: A = {
        left: 'left_a',
        right: 'right_a'
    }
    const a4: A = {
        left: 'left_a',
        right: 'right_a',
        other: 'other' // 这里就会报错,因为 A 类型不包含 other 属性(其实是第一次声明变量做了严格检查)
    }
    const a5: A = obj1 // 这样不会报错,因为obj1声明时并没有赋值给a5
    
    // 再看 B 类型
    const obj2 = {
        left: 'left_b',
        right: 'right_b',
        other: 'other'
    }
    const b1: B = {
        left: 'left_b' // 这里会报没有 right 属性的错
    }
    const b2: B = {
        left: 'left_b',
        right: 'right_b'
    }
    const b3: B = {
        left: 'left_b',
        right: 'right_b',
        other: 'other' // 这里会报 B 类型不包含 other 属性
    }
    const b4: B = obj2 // 这里不会报错
    
    // 例子 2 使用 type 定义有重复 key 的类型
    type A = {
        name: string,
        id: number
    }
    type B = {
        id: string,
        age: number
    }
    // C 只包含 A 或者只包含 B 或者包含 A + B 都可
    type C = A | B
    const c1: C = {
        name: 'rourou',
        id: '100', // 这里 id 定义成 number 也可
        age: 18
    }
    type D = A & B
    const d1: D = {
        name: 'rourou',
        id: 100, // 这里会报错 string 和 number 的交集是 never
        age: 18
    }
    
    // 例子 3 使用 type 定义有重复 key 的类型,但该重复 key 是一个方法
    // 结果是方法的参数会合并
    type A = {
        name: string,
        methods: (a: string) => void
    }
    type B = {
        age: number,
        methods: (a: number) => void
    }
    type C = A | B
    type D = A & B
    const d1: D = {
        name: 'rourou',
        age: 18,
        methods: (a) => {
            // 这里 a 的类型是 string | number
            console.log(a)
        }
    }
    const d1: C = {
        name: 'rourou',
        age: 18,
        methods: (a) => { // 这里会报错 Parameter 'a' implicitly has an 'any' type.意思就是 a的类型是 any
            console.log(a)
        }
    }
    
  • 使用 interface 模拟 &

    interface A {
        name: string,
        id: number
    }
    // Interface 'B' incorrectly extends interface 'A'.  
    // Types of property 'id' are incompatible 不相容的.     
    // Type 'string' is not assignable to type 'number'.
    interface B extends A { // 会报上面的错
        age: number,
        id: string
    }
    
  • interface 使用 &

    interface A {
        name: string
    }
    interface B {
        age: number
    }
    type C = A & B
    const c: C = {
        name: 'rourou',
        age: 18
    }