交叉类型 &

有类型A的特性,也有类型B的特性

  1. /* 交叉类型 */
  2. interface Mother {
  3. name: string
  4. hug(): void
  5. }
  6. interface Teacher {
  7. name: string
  8. teach(): void
  9. }
  10. type MotherAndTeacher = Mother & Teacher
  11. // mt 则同时拥有了hug和teach的方法
  12. let mt: MotherAndTeacher
  13. mt.hug()
  14. mt.teach()

image.png

答案

bamboo
12

解析

交叉类型是将多个类型合并为一个类型。这让我们可以把现有的多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性。
所以函数 getAnimalInfo 的形参 animal 的类型为 Panda & Koala 即
{ name: string; food: string; age: number; }
题目比较简单,答案为 bamboo,12。

ts 中的 typeof

/* ts 中的 typeof */
// 这是原场景,有很多冗余部分,比如修改类型结构无需维护多套
type People_5301 = {
    name: string
    age: number
}
let mmo_5301: People_5301 = {
    name: 'a',
    age: 18
}

function printName(p: People_5301) {
    console.log(p.name)
}

// 使用typeof关键字,只需要维护一套

let mmo_5302 = {
    name: 'a',
    age: 18,
    gender: 'm'
}

type People_5302 = typeof mmo_5302 

function printName(p: People_5302) {    // 该类型则 = mmo_5302
    console.log(p.name)
}

image.png

答案

正确

解析

animal 的类型为 typeof panda 即
{ name: string; age: number; }
题目比较简单,答案为正确。

索引访问操作符

/* 索引访问操作符 */
interface People_5303 {
    name: string
    age: number
    job: {
        name: string
        type: string
    }
    hobbies:{
        name: string,
        timesPerWeek: number
    }[]
}

// 取People_5303的job结构
let mmo_5303: People_5303['job'] = {
    name: 'a',
    type: 'teacher'
}

// 第二种索引方式,取数组结构内的某一属性,此处无需考虑取的下标是第几个,因为都是一样的
let swimTimesPerWeek: People_5303['hobbies'][0]['timesPerWeek'] = 3

image.png

答案

错误

解析

使用 Animal.info.name 来声明函数 getAnimalName 的返回值类型是错误的。
无法访问 Animal.info,因为 Animal 是类型,不是命名空间。
正确的表示方式为
Animal[‘info’][‘name’]

keyof 索引类型查询操作符

/* keyof 索引类型查询操作符 */
interface People_5304 {
    name: string
    age: number
    gender: 'male' | 'female'
}

type PeopleKey_5304 = 'name' | 'age' | 'gender' //常见写法
type PeopleKey_5305 = keyof People_5304  // 使用keyof关键字,效果等同于上面

function getPeopleValueByKey(p: People_5304, key: PeopleKey_5305) {
    return p[key]
}

image.png

答案

C

解析

keyof 为索引类型查询操作符。
keyof T 的结果为 T 上已知的公共属性名的联合。
变量 panda 的类型为 typeof Animal 即
“name” | “age”
所以正确答案为 C。

映射类型 in

/* 映射类型 */
interface People_5306 {
    name: string
    age: number
    gender: 'male' | 'female'
}

type PeopleKey_5306 = 'name' | 'age' | 'gender'

type PartialPeople_5306 = {
    [K in PeopleKey_5306]?: People_5306[K]  // 使用in操作符,将PeopleKey的每一项作为可选项
}

// 报错,缺少age、gender
let mmo_5306: People_5306 = {
    name: 'mmo'
}

// 正确, 每一项都是可选项
let aab_5306: PartialPeople_5306 = {
    name: 'mmo'
}

// 去除掉PeopleKey,最终可简写为
type PartialPeople_5307 = {
    [K in keyof People_5306]?: People_5306[K]
}

// 另一种泛型写法, 用于将任何类型T都转化为可选类型T
type Part<T> = {
    [K in keyof T]?: T[K]
}
let ccd:Part<People_5306> = {   // 泛型使用方式,实现同样的效果
    name: 'mmo'
}

image.png

答案

正确

解析

接口 Animal 的类型为
{ name: string; age: number; }
Option 的作用是将 T 的属性变为可选的。 所以 Option 的类型为
{ name?: string; age?: number; }
所以语法是正确的。

条件类型

/* 条件类型 */
type Beef = { beefWight: number }
type Fish = { fishWight: number }
type Lamb = { lambWight: number }

type StoneBaked<T> = T & {
    stoneTemperature: number
}
type FireBaked<T> = T & {
    fireTemperature: number
}

// 如果 传入的是Beef,则使用的是StoneBaked...
type Baked<T> = 
    T extends Beef ? StoneBaked<T> :
    T extends Fish ? FireBaked<T> :
        StoneBaked<T>

// 每个声明都拥有自己的方法
let b: Baked<Beef>
let f: Baked<Fish>
let l: Baked<Lamb>

image.png

答案

any
number
string

解析

类型 Condition 的条件判断流程。简单如下

Condition(`接收一个类型 T`) {
    if (`T 包含 Panda 的结构类型`) {
        return `number`;
    } else {
        if (`T 包含 Koala 的结构类型`) {
            return `string`;
        } else {
            return `any`;
        }
    }
}

所以 Condition 的结果为 any。 Condition 的结果为 number。Condition 的结果为 string。