TypeScript | 第五章:高级类型(上篇)

265 阅读3分钟

「这是我参与11月更文挑战的第14天,活动详情查看:2021最后一次更文挑战

TypeScript系列学习笔记:
TypeScript | 第一章:环境搭建及基础数据类型
TypeScript | 第二章:类、接口和之间的关系
TypeScript | 第三章:函数、泛型和枚举
TypeScript | 第四章:命名空间和模块
TypeScript | 第六章:理解声明合并,以及编写声明文件
TypeScript | 第七章:配置文件说明

1. 交叉类型

交叉类型是将多个类型合并为一个类型,用符号"&"表示。

// 交叉类型实现的方式 extend(Person,Loggable) == Person & Loggable
function extend<T, U>(first: T, second: U): T & U {
    let result = <T & U>{};
    for (let id in first) {
        (<any>result)[id] = (<any>first)[id];
    }
    for (let id in second) {
        if (!result.hasOwnProperty(id)) {
            (<any>result)[id] = (<any>second)[id];
        }
    }
    return result;
}

2. 联合类型

联合类型表示一个值可以是几种类型之一,用符号"|"分隔每个类型。

// 联合类型:padding若声明为any,编译能通过,但运行时会报错。
function padLeft(value: string, padding: string | number) {
    if (typeof padding === "number") {
        return Array(padding + 1).join(" ") + value;
    }
    if (typeof padding === "string") {
        return padding + value;
    }
    throw new Error(`Expected string or number, got '${padding}'.`);
} 
// 若值为联合类型,只能访问此联合类型的所有类型里共有的成员
interface Bird{
	fly();
  layEggs();
}
interface Fish{
	swim();
  layEggs();
}
function getPet():Bird|Fish{}
let pet = getPet();
pet.layEggs() // 正确,只能访问共有的成员
pet.swim()    // 错误

3. 自动类型推断

1. typeof

TypeScript可以将typeof识别为一个类型保护,可以直接在代码里检查类型了。

let num:number|string = Math.random()>0.2?1:'1'
// 类型必须是:"number""string""boolean""symbol"
if(typeof num ==='number'){ // 这里称为typeof类型保护
	num+=1
}

2. instanceof

nstanceof类型保护是通过构造函数来细化类型的一种方式。

let num:number|string = Math.random()>0.2?new Number(1):new String('1')

if(num instanceof Number){ // 称为instanceof类型保护
	num+=1
}

3. 浏览器API

document.onmousedown = e=>console.log(e) // 能自动推动出e为MouseEvent

4. 其他方式

let n = 1 ;    //ts自动推断出n为number类型

let arr = [1]  // 内部有数据,能推断出正确类型
arr.push(2)    // 正确
arr.push('3')  // 错误,参数是string类型

let arr2 = []  // 未声明类型,默认为any[]
arr2.push(1)
arr2.push('2')

4. null 和 undefined

默认情况,类型检查器认为nullundefined可以赋值给任何类型,它们是其它类型的一个有效值。

--strictNullChecks标记可以解决,声明变量时不会自动包含null或 undefined。可选参数会自动加上| undefined

let s = "a";
s = null;  // 错误,null 不能赋值给string
let sn:string|null = 'b'
sn = null; // 正常

5. 类型断言

告诉ts这是什么类型,它都信。

let obj = Math.random()>0.2?[]:1;

// 方式一:"<>" 表示
(<number[]>obj).push(1)

// 方式二:as表示
(obj as number[])obj.push(1)

6. 类型别名

类型别名会给一个类型起个新名字。 类型别名有时和接口很像,但是可以作用于原始值,联合类型,元组以及其它任何你需要手写的类型。

型别名可以表示很多接口表示不了的类型, 比如字面量类型(常用来校验取值范围)。

类型别名不能出现在声明右侧的任何地方。

type Color = 'red'|'yellow'|'green'
type Num = 1|2|3
type Name = '张三'|'李四'

let a:Color = 'black' // 报错,Color类型中没有black

interface A{a:number}
type B = A | {b:number}
type C = A & {c:number}

7. 索引类型

ts中的keyof和他类似, 可以用来获取对象类型的键值。

// T[K], 索引访问操作符
function getProperty<T, K extends keyof T>(o: T, name: K): T[K] {
    return o[name]; // o[name] is of type T[K]
}
type A = keyof {a:1,b:2}  // 'a'|'b'
type B = keyof [1,2]   // '1'|'2'|'push'...,不仅获取内容,还获取到Array原型上的方法

8. 总结

至此完成了高级类型的学习,不完善的地方后续陆续补充。