TypeScript学习笔记 | 青训营笔记

108 阅读6分钟

这是我参与「第四届青训营 」笔记创作活动的的第15天

TypeScript

TypeScript发展历史

  • 2012-10:微软发布了 TypeScript 第一个版本(0.8)
  • 2014-10:Angular 发布了 2.0 版本,它是一个基于 TypeScript 开发的前端框架
  • 2015-04:微软发布了 Visual Studio Code,它内置了对 TypeScript 语言的支持,它自身也是用 TypeScript 开发的
  • 2016-05:@types/react 发布,TypeScript 可以开发 React 应用以及Node.js应用
  • 2020-09:Vue 发布了 3.0 版本,官方支持 TypeScript
  • 2021-11:v4.5版本发布

什么是TypeScript

官方定义:
TypeScript is a typed superset of JavaScript that compiles to plain JavaScript. Any browser. Any host. Any OS. Open source.
TypeScript 是 JavaScript 的类型的超集,它可以编译成纯 JavaScript。编译出来的 JavaScript 可以运行在任何浏览器上。
TypeScript 编译工具可以运行在任何服务器和任何系统上。TypeScript 是开源的。

TypeScript是 JavaScript 的一个超集,主要提供了类型系统和对 ES6 的支持

为什么使用TypeScript

  • JavaScript与TypeScript的区别
    • 不同点:JavaScript是一种动态类型,执行阶段就确定了类型匹配。而TypeScript静态类型,执行前就编译完成
    • 相同点:弱类型语言
  • TypeScript的优势
    • 静态类型
      • 可读性增强:基于语法解析TSDoc,ide增强(自动生成文档、类型提示、代码补全)
      • 可维护性增强:在编译阶段暴露大部分错误(语法、类型)
      • 在多人合作的大型项目,获得更好的稳定性和开发效率
    • JavaScript的超集
      • 包含于兼容所有JS的特性,支持共存
      • 支持渐进式引入与设计

TypeScript基本语法

1.基本语法

变量名:变量类型 = 值

const q:string = 'string'  //字符串
const w:number = 1  //数字
const e:boolean = 1  //布尔值
const r:null = 1  //null
const t:undefined = 1  //undefined

2.对象类型

const bytedancer:IBytedancer={
    jovID:102922,
    name:'Lin',
    sex:'man',
    age:28,
    hobby:'swimming',
}

interface IBytedancer{
    // 只读属性:约束属性不可在对象初始化外赋值
    readonly jobID:number;
    name:string;
    sex:'man'|'woman'|'other';
    age:number;
    // 可选属性?:定义改属性可以不存在
    hobby?:string;
    // 任意属性:约束所有属性都必须是该属性的子类型
    [key:string]:any;
}

任意值 any

  有时,我们在编程阶段还不清楚变量的类型。 这些值可能来自于动态的内容,比如来自用户输入或第三方代码库。 这种情况下,我们不希望类型检查器对这些值进行检查而是直接让它们通过编译阶段的检查。 那么我们可以使用any类型来标记这些变量。

3.函数类型

// 第一种:
function add(x,y) {
    return x+y;
}
const mult=(x,y) => x*y;

// 第二种:
function add(x:number,y:number):number{
    //即定义x,y,返回值的类型为number
    return x+y;
}
const mult:(x:number,y:number)=>number=(x,y)=>x*y;
//(x:number,y:number)=>number返回值定义类型使用=>符号

// 第三种:
//定义接口类型然后赋值给变量
interface IMult{
    (x:number,y:number):number;
}
const mult:IMult=(x,y)=>x*y;

4.数组类型(一般使用前两种)

// 类型+方括号表示
type IArr1=number[];
// 泛型表示
type IArr2=Array<string | number | Record<string,number>>;
// 元组表示,表每个元素的类型
type IArr3=[number,number,string,string]
// 接口表示
interface IArr4{
    [key:number]:any;
}
const arr1:IArr1=[1,2,3,4,5,6];
const arr2:IArr2=[1,2,'3','4',{a:1}];
const arr3:IArr3=[1,2,'3','4'];
const arr4:IArr4=['string',()=>null,{},[]];

5.补充类型

// 空类型,表示无赋值
type IEmptyFunction=()=>void;
// 任意类型,是所有类型的子类型
// 枚举类型:支持枚举值到枚举名的正,反向映射
enum EnumExample{
    add='+',
    mult='*',
}
EnumExample['add']==='+';
EnumExample['+']==='add';

enum EColor{Mon,Tue,Thu,Fri,Sat,Sun};
EColor['Mon']===0;
EColor[0]==='Mon';
// 泛型
type INumArr=Array<number>;

6.泛型

function getRepeatArr(target){
    return new Array(100).fill(target);
}
type IGetRepeatArr={target:any}=>any[];

/*不预先指定具体类型,而在使用时候再指定类型的一种特性*/
type IGetRepeatArr=<T>{target:T}=>T[];

/* 泛型接口&多泛型*/
interface Ix<R,U>{
    key:T;
    val:U;
}
/* 泛型类*/
class  IMan<T> {
    instance:T;
}
/*泛型别名 */
type ITypeArr<T>=Array<T>

/*泛型约束:限制泛型必须符号字符串 */
type IGetRepeatStringArr=<T extends string>(target:T)=>T[];
const getStrArr:IGetRepeatStringArr=target=>new Array(100).fill(target);
/*报错:类型“number”的参数不能赋给“string”的参数 */
getStrArr(123);

/*泛型参数默认类型 */
type IGetRepeatArr<T=number>=(target:T)=>T[];
const getRepeatArr:IGetRepeatArr=target=>new Array(100).fill(target);
/*报错:类型“string”的参数不能赋给类型“number”的参数 */
getRepeatArr('123');

TypeScript高级类型

1.什么是接口

  TypeScript的核心原则之一是对值所具有的_结构_进行类型检查。 它有时被称做“鸭式辨型法”或“结构性子类型化”。 在TypeScript里,接口的作用就是为这些类型命名和为你的代码或第三方代码定义契约。

2.联合/交叉类型

  • 联合类型:A | B,联合类型表示一个值可以是几种类型之一
  • 交叉类型:A & B, 多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性
/*原始表达方式*/
const bookList=[{
    author:'xiaoming',
    type:'history',
    range:'2002-2021'.
},{
    author:'xiaoli',
    type:'story',
    theme:'love',
}]
/* 改进表达方式 */
type IBookList=Array<{
    author:string;
}&(
    {
        type:'history';
        range:string;
    }|{
        type:'story';
        theme:string;
    }
)>

3.类型保护与类型守卫

  仅当两个类型没有重合点时,才需要写类型守卫。其余情况obj.type可判断数据类型,即可自动识别

interface A{ a:1,a1:2 }
interface B{ b:1,b1:2 }
/* 类型守卫:定义一个函数,它的返回值是一个类型谓词,生效范围为子作用域 */
function getIsA(arg:A | B):arg is A{
    return !!(arg as A).a;
    /* as是一个类型断言,判断为A ,返回布尔值*/
}
function log2(arg: A | B){
    if(getIsA(arg)){
        console.log(arg.a1);
    }else{
        console.log(arg.b1);
    }
}

类型断言
类型断言就是手动指定一个类型的值,有两种形式

  1. 尖括号语法
let str: any = "this is a string";
let strLength: number = (<string>str).length;
  1. as语法
let str: any = "this is a string";
let strLength: number = (str as string).length;
interface IMerge{
    <T extends Record<string,any>>(sourceObj:Partial<T>,targetObj:T):T;
}
/* IPartial内置类型 */
type IPartial<T extends Record<string,any>>={
    [P in keyof T]?:T[P];
}

type IKeys=keyof{a:string;b:number};

  • 索引类型:关键字【keyof】,其相对于取值对象中的所有key组成的字符串字面量
  • 关键字【in】,其相对于取值字符串字面量中的一种可能,配合泛型P,即表示每个key
  • 关键字【?】,通过设定对象可选选项,即可自动推导出子集类型

4.函数返回值类型

type IDelayCall=<T extends()=>any>

工程应用

浏览器Web、Node.js

webpack

  1. 配置webpack loader相关配置
  2. 配置tsconfig.js文件
  3. 运行webpack启动/打包
  4. loader处理ts文件时,会进行编译与类型检查

Node.js

  1. 使用TSC编译
    • 安装Node与npm
    • 配置tsconfig.js文件
    • 使用npm安装tsc
    • 使用tsc编译得到js文件

总结

  学习完本次青训营的TypeScript课程,老师讲的非常好,很详细,我这个小白也有了进一步的理解。不过光靠听可能不够,还是需要多实践动手敲代码才能真正的理解。