TypeScript 笔记 参加字节跳动的青训营时写的笔记。这部分是林皇老师讲的课。(过年偷懒,项目爆肝后,重新整理笔记)
个人博客 (欢迎光临):TypeScript 笔记
1. 简介
静态类型
可读性增强:基于语法解析 TS Doc,IDE 增强
可维护性增强:在编译阶段暴露大部分的错误(类型匹配错误、拼写错误等)
JS 的超集
包含兼容所有 JS 特性
支持渐进式引入和升级,支持与 JS 共存
动态类型:数据类型不是在编译阶段决定的,而是在运行阶段决定的
静态类型:数据类型是在编译期间或运行之前确定的,即编写代码时需要定义变量的类型。
强类型:变量指定了数据类型之后,如果不经过强制类型转换,那么该变量永远是这个数据类型
弱类型:数据类型可以被忽略,一个变量可以赋予不同数据类型的值。即如果给整型变量 a 赋值字符串,则 a 变成字符串类型。
更多
2. 基本语法 2.1 基础数据类型 JS :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 const s = "Hello" ;const num = 1 ;const b = true ;const n = null ;const u = undefined ;
TS :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 const s : string = "Hello" ;const num : number = 1 ;const b : boolean = true ;const n : null = null ;const u : undefined = undefined ;
2.2 对象类型 1 2 3 4 5 6 7 8 interface IPeople { readonly id : number ; name : string ; sex : "male" | "female" ; age : number ; hobby?: string ; [key : string ]: any ; }
2.3 函数类型 1 2 3 4 5 6 7 8 9 10 11 12 13 function add (x : number , y : number ): number { return x + y; }const add : (x : number , y : number ) => number = (x, y ) => x + y;interface IAdd { (x : number , y : number ): number ; }const add : IAdd = (x, y ) => x + y;
2.3.1 函数重载 1 2 3 4 5 6 7 8 9 function getDate (type : "string" , timestamp?: string ): string ;function getDate (type : "date" , timestamp?: string ): Date ;function getDate (type : "string" | "date" , timestamp?: string ): Date | string { const date = new Date (timestamp); return type === "string" ? date.toLocaleDateString () : date; }const x = getDate ("date" ); const y = getDate ("string" , "2022-02-01" );
上面的函数的目的就是第一个参数是 date
时,返回 Date 对象;是 string
的话,则返回时间戳字符串。
没有上面两个定义函数的情况:
2.4 数组类型 1 2 3 4 5 6 7 8 9 10 11 12 13 type IArr1 = number []; type IArr2 = Array <string | number | Record <string , number >>; type IArr3 = [number , string , number ];interface IArr4 { [key : number ]: any ; }
1 2 3 4 const arr1 : IArr1 = [1 , 1 , 2 ];const arr2 : IArr2 = [1 , "hello" , { age : 21 }];const arr3 : IArr3 = [1 , "hello" , 1 ];const arr4 : IArr4 = ["string" , () => null , []];
2.5 泛型 泛型:不提前指定具体类型,而是在使用时才指定类型
2.5.1 泛型函数 1 type IGetArr = <T>(target : T ) => T[];
1 2 3 4 5 6 7 8 9 10 function getRepeatArr (target ) { return new Array (10 ).fill (target); }type IGetArr = <T>(target : T ) => T[];const GetArr : IGetArr = getRepeatArr;const stringArr = GetArr ("Hello" );const numArr = GetArr (10 );
2.5.2 泛型接口 1 2 3 4 interface IX<T, U> { key : T; val : U; }
2.5.3 泛型类 1 2 3 class IX <T> { key : T; }
2.5.4 泛型别名 1 type ITypeArr <T> = Array <T>;
2.5.5 泛型约束 1 type IGetRepeatStringArr = <T extends string >(target : T ) => T[];
2.5.6 泛型参数默认 1 type IGetRepeatArr <T = number > = (target : T ) => T[];
2.6 其他类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 type IEmptyFunction = () => void ;type IAnyArr = any ;enum EnumExample { add = "+" , mul = "*" , }EnumExample ["add" ] === "+" ;EnumExample ["+" ] === "add" ;type IOddNum = 1 | 3 | 5 | 7 | 9 ;
3. 高级类型 3.1 联合/交叉类型 首先,假设一个情景,你有收藏书籍的兴趣,但是只收藏历史书和故事书,而且历史书需要记录历史范围,而故事书则是需要记录主题。
为书籍列表编写类型(如下图所示):可以发现类型声明繁琐,存在较多变量
通过联合/交叉类型可以实现优化
联合类型 :IA | IB,表示一个值可以是 IA 类型或 IB 类型
交叉类型 :IA & IB,多种类型叠加成一种类型,包含了所需的所有类型的特性
优化后:
3.2 类型保护和类型守卫 3.2.1 类型保护 1 2 3 4 5 6 7 8 9 10 11 12 13 function reverse (target : string | Array <any > ) { if (typeof target === "string" ) { return target.split ("" ).reverse ().join ("" ); } if (target instanceof Object ) { return terget.reverse (); } }
联合/交叉类型中的书籍只有历史和故事两种类型,所以可以实现自动类型推断
1 2 3 4 5 6 7 8 function logBook (book : IBookList ) { if (book.type === "history" ) { console .log (book.range ); } else { console .log (book.theme ); } }
3.2.2 类型守卫 访问联合类型时,仅能访问联合类型中的交集部分。 所以下面的例子会报错
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 interface IA { a : 1 ; a1 : 2 ; }interface IB { b : 1 ; b1 : 2 ; }function log (arg : IA | IB ) { if (arg.a ) { console .log (arg.a1 ); } else { console .log (arg.b1 ); } }
通过类型守卫则可以解决问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 interface IA { a : 1 ; a1 : 2 ; }interface IB { b : 1 ; b1 : 2 ; }function getIsIA (arg : IA | IB ): arg is IA { return !!(arg as IA ).a ; }function log (arg : IA | IB ) { if (getIsIA (arg)) { console .log (arg.a1 ); } else { console .log (arg.b1 ); } }