写点什么

TypeScript | 第五章:高级类型

用户头像
梁龙先森
关注
发布于: 2020 年 12 月 25 日
TypeScript | 第五章:高级类型

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. 映射类型

映射类型比较像修改类型的工具函数。

infer:待推断/延迟推断,根据实际情况推断类型。

1. Readonly
// 定义: 把每个属性都变成只读
type Readonly<T>={
readonly (P in keyof T):T[P]; // 循环设置泛型T的属性为只读
}
type A = {a:number, b:string}
type AA = Readonly<A>
2. Partial<T>
// 定义:让属性都变成可选
type Partial<T> = {
[P in keyof T]?:T[P]
}
type A = {a:number, b:string}
type AA = Partial<A> // { a?: number; b?: string;}
3. Required<T>
// 定义:让属性都变成必选
type Required<T> = {
[P in keyof T]-?:T[P]
}
type A = {a?:number, b?:string}
type A = Required<A> // { a: number; b: string;}
4. Pick<T,K>
// 定义:只保留自己选择的属性, K代表要保留的属性键值
type Pick<T,K extends keyof T> = {
[P in K]:T[P]
}
type A = Pick<{a:number,b:string,c:boolean}, 'a'|'b'>
type AA = Pick<A, 'a'|'b'> // {a:number,b:string}
5. Omit<T,K> 
// 定义: 实现排除已选的属性
type Omit<T,K extends keysof T> = Pick<T, Exclude<keyof T, K>>;
type A = {a:number, b:string}
type AA = Omit<A, 'a'> // {b:string}
6. Record<K,T>
// 定义:Construct a type with a set of properties K of type T
type Record<K extends keyof any, T> = {
[P in K]: T;
};
type AA = Record<string, string> // 等价{[x:string]:string}
7. Exclude<T,U>
// 定义:过滤T中和U相同(或兼容)的类型
type Exclude<T, U> = T extends U ? never : T;
type A = {a:number, b:string}
type AA = Exclude<number|string, string|number[]> // number
// 兼容
type A1 = Exclude<number|string, any|number[]> // never , 因为any兼容number, 所以number被过滤掉
8. Extract<T,U>
// 定义:提取T中和U相同(或兼容)的类型
type Extract<T, U> = T extends U ? T : never;
type A = {a:number, b:string}
type AA = Extract<number|string, string|number[]> // string
9. NonNullable
// 定义:剔除T中的undefined和null
type NonNullable<T> = T extends null | undefined ? never : T;
type A = NonNullable<number|string|null|undefined> // number|string
9. ReturnType
// 定义:获取返回的返回类型
type ReturnType<T extends (...args:any)=>any> = T extends (...args:any)=>infer R?R:any
type A= ReturnType<()=>number> // number
10. InstanceType

返回T的实例类型。

ts中类有2种类型, 静态部分的类型和实例的类型, 所以T如果是构造函数类型, 那么InstanceType可以返回他的实例类型:

// 定义:获取构造函数类型的返回类型
type InstanceType<T extends new (...args: any) => any> = T extends new (...args: any) => infer R ? R : any;
interface A{
a:HTMLElement;
}
interface AConstructor{
new():A;
}
function create (AClass:AConstructor):InstanceType<AConstructor>{
return new AClass();
}
11. Parameters<T>
// 定义:获取函数参数类型,返回类型为元祖, 元素顺序与参数顺序一样.
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;
interface A{
(a:number, b:string):string[];
}
type AA = Parameters<A> // [number, string]
12. ConstructorParameters<T>
// 定义:获取构造函数的参数类型,T:构造函数类型
type ConstructorParameters<T extends new (...args: any) => any> = T extends new (...args: infer P) => any ? P : never;
interface MyConstructor{
new(a:number):number[];
}
type AA = ConstructorParameters<MyConstructor> // [number]

9. extends

// 条件类型:表示类型是不确定的,U可以表示T,则返回X,否则Y
T extends U ? X : Y
type A = string extends 'a'?string:'a' // 'a'不能表示string类型,输出 'a'
type B = 'a' extends string?string:'a' // string能表示'a',输出 string
// 类型过滤: 从T过滤掉可以赋值给U的
type Diff<T,U> = T extends U?never: T;
type C = Diff<'a'|'b'|'c','b'|'e'> // type C = 'a'|'c'
// 过滤掉null,undefined
type NotNull = Diff<T,null | undefined>
type D = NotNull<string|number|null> // type D = string|number

10. 总结

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



发布于: 2020 年 12 月 25 日阅读数: 543
用户头像

梁龙先森

关注

寒江孤影,江湖故人,相逢何必曾相识。 2018.03.17 加入

1月的计划是:重学JS,点个关注,一起学习。

评论

发布
暂无评论
TypeScript | 第五章:高级类型