Typescript入门 | 青训营笔记

124 阅读5分钟

Typescript入门 | 青训营笔记

这是我参与「第四届青训营 」笔记创作活动的的第十三天。今天的课堂内容讲的是typescript的入门,感觉收获颇丰。以前稍微写过一点typescript,但是也就只是用到了ts的类型而已,距离如何正确且优雅的使用ts还相距甚远,今天林皇老师的课《Typescript入门》让我觉得干活满满。特此记录下笔记,帮助自己学习ts。

Typescript发展史

从2012年10月微软发布TypeScript第一个版本至今已有十年时间,这期间Angular、React、Vue三大主流的前端框架都相继支持TypeScript。甚至连vue3的底层都使用TS进行编写,可见TypeScript正在逐渐成为主流。

image.png

为什么要使用TypeScript

Typescript其实是源于JavaScript

  • JavaScript
    • 动态类型:运行阶段才能够确定一个变量的类型,变量的类型可以随时发生变化
    • 弱类型:能进行隐式类型装换,比如c语言运行1+"1"就会报错,而js运行1+"1"会得到"11"
  • TypeScript
    • 静态类型:申明变量时就确定了变量的类型,变量的类型不可以发生改变。
    • 弱类型:能进行隐式类型装换,比如c语言运行1+"1"就会报错,而Ts运行1+"1"会得到"11"

image.png

而静态类型的TS相较于动态类型的JS会有哪些优点呢?

image.png

使用好TS,能帮助我们增强项目的可读性和可维护性。帮助我们更优雅的编写代码。

基础语法

基本数据类型

在变量名后面加上:变量类型来定义变量的类型

image.png

对象数据类型

使用interface(接口)来定义对象类型。

  • readonly:表示只读属性,表示属性不可以在对象初始化之外进行赋值
  • ?:可选属性,表示属性可以存在也可以不存在
  • sex:"man" | "woman" | "other":表示取值只能为man、woman、other中的一个
  • any:是ts特有的一个类型,表示所有类型,任何类型。 image.png

image.png

函数类型

我们用js编写函数时一般这样写

function add(x,y){
    return x+y
}

const mult = (x,y)=>x*y

而用ts编写函数时,可以给形参和函数返回值加上类型

function add(x:number,y:number):number{
    return x+y
}

const mult:(x:number,y:number)=>number = (x,y)=>x*y

如果嫌在函数参数比较多,在参数上写类型会让整个代码很长,不好看,我们可以这样写

interface IMult{
    (x:number,y:number):number
}

const mult:IMult = (x,y)=>x*y

数组类型

/*「类型+方括号」表示*/
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,{},[]];

补充类型

/*空类型,表示无赋值*/
type IEmptyFunction = () => void;
/*任意类型,是所有类型的子类型*/
type IAnyType = any;
/*枚举类型:支持枚举值到枚举名的正、反向映射*/
enum EnumExample {
    add = '+',
    mult = '*',
}
EnumExample[' add '] == '+'; EnumExample['+'] = 'add ';
enum ECorlor { Mon, Tue, Wed, Thu, Fri, Sat, Sun }; ECorlor['Mon'] == 0;
ECorlor[0] == 'Mon ';/*泛型*/
type INumArr = Array<number>;

泛型

作为一个“javaboy”,泛型在TS里的出现真的让我感到太舒服了。

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

当我们有一个函数

function getRepeatArr(target) {
    return new Array(100).fill(target);
}

我们想使用ts来限制传入的参数的类型和输出的数组类型一致,简单粗暴的写法可以这样写

type IGetRepeatArr = (target: any) => any[];

const getRepeatArr2:IGetRepeatArr = (target)=>new Array(100).fill(target);

但实际上这样简单粗暴的方式是达不到我们想要的效果的,我们需要传入的参数是number类型,那返回的是number的数组,但是上面这种简单粗暴的写法,传入的number类型却有可能返回的是string数组。因为any类型的意思是任意类型。

我们利用泛型可以这样写

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

const getRepeatArr2:IGetRepeatArrR = (target)=>new Array(100).fill(target);

通过泛型,不预先指定类型,而是在使用的时候再指定类型,来做到输入与输出的类型一致。

泛型约束

使用泛型的时候,可以使用泛型约束来将泛型限制在一定范围内。 使用extends关键字,限制泛型的类型。如下代码,限制泛型只能是string类型,则getSetArr方法使用IGetRepeatStringArr类型时,输入值只能为string,输入number就会报错

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

image.png

泛型参数默认类型

泛型可以使用=来设置默认的类型
getRepeatArr方法使用IGetRepeatArr类型时,没有设置泛型,则泛型默认为number,传入String类型的参数就会报错

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

image.png

当传入一个泛型后,默认类型被覆盖,报错就消失了

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

image.png