TypeScript | 青训营笔记

108 阅读5分钟

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

什么是TypeScript

  • TypeScript是由微软开发的一个开源的编程语言,它是JavaScript的超集,同时支持ES6的新特性。
  • TypeScript相较于JavaScript而言是一种强类型语言,对于有C/C++、java等拥有强类型特性编程语言基础的同学来说更容易理解。

TypeScript特点

  • 可读性强
  • 可维护性强
  • 兼容所有JS特性,支持共存
  • 支持渐进式引入与升级

数据类型及声明

基础语法

TS通过在声明时用:为一个变量指定数据类型

let a:string = "hello world";
console.log("a",a);

输出

a hello world

此处声明了一个string类型的变量a并进行赋值,如果为a赋值为非string类型值时会失败。 image.png image.png

基础数据类型

  • any:可以将变量声明为任意类型,相当于取消修饰变量的强类型特性,使用JS的弱类型。
  • number:数字类型。
  • string:字符串类型。
  • boolean:布尔型。
  • void:空类型。
  • undefined:用于初始化变量为未定义的值。
  • null:用于定义缺失值的类型。
  • object:对象类型。
  • enum:枚举类型。支持枚举值到枚举名的正反映射。

普通对象的声明

在声明对象的同时可以对内部值进行类型限定。

interface IPerson{
  readonly id:number,
  name:string,
  age:number,
  sex:"男"|"女"|"保密",
  hobby?:string,
  [other:string]:any
}
const zhangsan:IPerson={
  id:1,
  name:"张三",
  age:18,
  sex:"男"
}

在以上代码中,通过interface关键字定义一个模板类型IPerson,指定变量zhangsaIPerson类型的对象。
在定义中,通过readonly关键字使字段变为只读状态,设置sex字段时通过|符号分隔多个候选值限定可使用的值,设置hobby字段时使用?:表示该字段为可选项。
最后一行[other:string]:any声明了一个索引类型,表示该对象可以拥有其他属性,并定义其他属性的键为string类型,所有属性值为any类型的子类型。

函数的声明

可以对函数的参数已经返回值进行类型限定。

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;

以上代码均声明add函数接收两个number类型的参数xy,并限定函数的返回值也为number类型。

当限定函数返回值为void时,该函数可以没有返回值。

函数重载

可以重复声明同名函数但接收不同类型的参数或返回值实现函数重载。

function add(x:number,y:number,t:"number"):number;
function add(x:string,y:string,t:"string"):string;
function add(x:number|string,y:number|string,t:"string"|"number"):number|string{
   const res=t=="string"?(x as string).concat(y as string):(x as number)+(y as number);
   return res;
}
console.log(@1,add(1,2,,"number"));
console.log(@2,add("1","2","string"));

输出
image.png
在以上代码中先获取传入的t参数值判断数据类型,然后使用as关键字将对应的参数看做指定的类型进行运算并返回指定类型的结果。

数组的声明

在ts当中由于有类型限制,所以数组也有多种声明方式。

  • 类型+方括号

    let arr:number[];//声明一个number型数组
    
  • 泛型声明数组

    let arr:Array<string>;//声明一个string型数组
    let arr2:Array<Recard<number,string>>;
    
    以上代码第二行使用了高级类型Recard,指定该数组访问时的索引为number类型,但是该数组为一个 string类型的数组。
  • 元组

    let arr:[string,number,boolean];//声明一个元组,仅能存入3个元素,且限定每一位的元素类型
    
  • 接口表示数组

    interface IArr{
        [key:number]:boolean;//指定元素类型为boolean
    }
    let arr:IArr;
    

泛型

泛型由一个标识符进行类型占位,该标识符会捕获接受的参数类型并可以替代原类型名进行类型声明。

function fun<T>(info:T):T{
    return info;
}
const res=fun("hello world");
const res1=fun(123);
console.log(typeof res,typeof res1);

输出:string number
上述代码指定一个泛型T,当函数fun被调用并传递了参数info时,T会捕获参数info的数据类型并可以作为该类型的另一个名字进行同等操作。


在泛型中可以使用extends对泛型进行类型约束。

type IFun=<T extends number>(info:T)=>T;
let fun:IFun=info=>info;

以上代码首先使用type关键字将IFun指定为特定的复杂类型别名,并在类型定义中使用<T extends number>限制该类型函数传入的数据必须为number才可正常使用。 image.png


在泛型中使用=指定默认类型

type IFun<T=number>=(info:T)=>T;
const fun:IFun=info=>info;

在以上代码中将extends关键字改为=,同样指定该泛型的类型为number并限制参数类型。 image.png

高级数据类型

联合/交叉类型

  • 联合类型:在多个类型之间使用|表示值可以是几种类型之一
  • 交叉类型:在多个类型之间使用&表示将多种类型叠加成为一种类型,它包括所需类型的所有特征
type IPerson=Array<{
    readonly id:number
    name:string
  }&({
    hobby:"看书"
    book:string
  }|{
    hobby:"运动"
    sports:string
  })>
const arr:IPerson=[
  {id:1,name:"张三",hobby:"看书",book:"《小王子》"},
  {id:2,name:"李四",hobby:"运动",sports:"打篮球"}
]

上述代码中arr数组不可能拥有{id:3,name:"王五",hobby:"看书",book:"《西游记》",sports:"踢足球"}元素,即以|分隔的两个对象类型中的元素无法共存。

  • 访问联合类型时,为了保证程序安全,仅能访问联合类型的交集部分

总结

在学习ts的过程中,我感觉泛型尤为重要,但是也是比较难以理解的地方,它使代码能够编写的更加灵活但又不丢弃ts强类型的特点。