TypeScript入门 | 青训营笔记

127 阅读7分钟

这是我参与「第四届青训营 」笔记创作活动的的第十三天。 今天学习了《TypeScript入门这节课,通过这节课的学习,我认识到了TypeScript的基本语法以及一些简单的高级应用,TypeScript的语法和JavaScript十分相似,所以学习基本语法十分容易理解,而且编程语言基本思想都是互通的,只是在高级应用方面各有所长,总结,今天收获满满,学习了一门新的语言,还要继续加深学习粒度,加油!

本堂课重点内容

  • 为什么是TypeScript
  • 基本语法
  • 高级类型
  • 工程应用

详细知识点介绍

详细的笔记分享在文章最后,加油!坚持!

课后个人总结

TypeScript在语法上与Javascript很类似,而且TS的限制很多还需要转换,但是弱类型和强类型还是有很大的区别的,TS方便更准备的检查我们编码时语法上的错误,而且给程序的稳定性带来了很大的提升,而且使用JS判断类型需要typeOf,但是TS就不需要,数据类型是之前就规定好的。这也对数据类型有了严格的把控,不至于程序自判断失误。

笔记

TypeScript入门

一、为什么是TypeScript

1、TypeScript的发展历史

  • 2012-10:微软发布了TypeScript第一个版本(0.8)
  • 2014-10: Angular 发布了基于TypeScript 的2.0版本
  • 2015-04:微软发布了Visual Studio Code
  • 2016-05:@types/react发布,TypeScript可开发 React
  • 2020-09: Vue 发布了3.0版本,官方支持
  • TypeScript2021-11:v4.5版本发布

2、为什么是TypeScript

  • JS:动态类型、弱类型语言
  • TS:静态类型、弱类型语言

静态类型:在执行之前的编译时期就会进行类型的匹配。

动态类型:在执行阶段才会进行类型的匹配。

弱类型:在执行时可以进行隐式转化。

TS的优势:

  • 静态类型

    • 可读性增加:基于语法解析TSDoc,ide增强
    • 可维护性增强:在编译阶段暴露大部分错误
  • JS的超集

    • 包含于兼容所有JS特性,支持共存
    • 支持渐进式引入与升级

二、基本语法

1、基础数据类型

  • JS代码
/*字符串 */
const q = 'string' ;
/*数字*/
const w = 1;
/*布尔值*/
const e = true;
/* null */
const r = null;
/*undefined */
const t = undefined;
  • TS代码
/*字符串*/
const q: string = 'string';
/*数字*/
const w: number = 1;
/*布尔值*/
const e: boolean = true;
/* null */
const r: null = null;
/* undefined*/
const t: undefined = ndefined;

2、对象类型

const bytedancer: IBytedancer = {
    jobId: 9303245,
    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;
}
/*报错:无法分配到“jobId",因为它是只读属性*/
bytedancer.jobId = 12345;
/*成功:任意属性标注下可以添加任意属性*/
bytedancer.plateform = 'data';
/*报错:缺少属性“name" , hobby可缺省*/
const bytedancer2: IBytedancer = {
    jobId: 89757,
    sex: 'woman ',
    age: 18,
}

3、函数类型

  • 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) => × * y;
interface IMult {
    (x: number, y: number): number;
}
const mult: IMult = (x,y) => x * y;

4、函数重载

/*对getDate函数进行重载, timestamp为可缺省参数*/
function getDate(type: 'string ' , timestamp?: string ): string;interface IGetDate {
    (type: 'string ', timestamp?: string): string;
    (type: 'date' , timestamp?: string): Date;
    (type: 'string' | 'date ', timestamp?: string): Date | string;
}
/*不能将类型"(type: any, timestamp: any) => string | Date"分配给类型IGetDate”。
不能将类型“string | Date"分配给类型“string"。
不能将类型"Date"分配给类型“string”。ts (2322)*/
const getDate2: IGetDate = (type,timestamp)=> {
    const date = new Date(timestamp);
    return type a= 'string' ? date.toLocaleString() : date;
}

5、数组类型

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

6、TypeScript的补充类型

/*空类型,表示无赋值*/
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 ';

7、TypeScript泛型

/*泛型*/
type INumArr = Array<number>;
/*不预先指定具体的类型,而在使用的时候再指定类型的一种特性*/
type IGetRepeatArrR = <T>(target: T) => T[];
/*泛型接口&多泛型*/
interface IX<T,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' );

8、类型别名 & 类型断言

/*通过type关键字定义了IObjArr的别名类型*/type 10bjArr = Array<{
    key: string;
    [objKey: string] : any;
}>
function keyBy<T extends IObjArr>(objArr: Array<T>){
    /*未指定类型时,result类型为*/
    const result = objArr.reduce((res, val, key) => {
        res [key] = val;
        return res;
    }, {});
    /*通过as关键字,断言result类型为正确类型*/
    return result as Record<string,T>;
}

9、字符串/数字 字面量

/*允许指定字符串/数字必须的固定值*/
/*IDomTag必须为html、body、div、span中的其一*/
type IDomTag = 'html' | 'body' | 'div' | 'span ';
/* IOddNumber必须为1、3、5、7、9中的其一*/
type IOddNumber = 1 | 3 | 5 | 7 |9;

三、高级类型

1、联合 / 交叉类型

为书籍列表编写类型

const bookList = [{
    author: 'xiaoming ',
    type: 'history' ,
    range: 2UUl-LUL,
},{
    author:X1aoIi,
    type:'story ',
    theme: 'love' ,
}]

==> 类型声明繁琐,存在较多重复

interface IHistoryBook {
    author: string;
    type: string;
    range : string
}
interface IStoryBook {
    author: string;
    type: string;
    theme: string;
}
type IBookList = Array<IHistoryBook | IStoryBook>;

所以这里可以使用联合类型或者交叉类型进行编写

联合类型

IA | IB; 联合类型表示一个值可以是几种类型之一

const bookList = [{
    author: 'xi aoming' ,
    type: 'history ',
    range: 2UUl-LUL,
}, {
    author: 'xiaoli',
    type: 'story' ,
    theme : 'love' ,
}]

交叉类型:

IA & IB ; 多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性

type IBookList = Array<{
    author: string;
}&({
    type : 'history';
    range: string;
} | {
    type: 'story ';
    theme: string;
})>

2、类型保护与类型守卫

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 log2(arg: IA |IB) {
    if (getIsIA(arg)) {
        console.log(arg.a1)
    }else {
        console.log(arg.b1);
    }
}

3、高级类型

/**
  * 实现merge函数类型
  * 要求sourceObj必须为targetObj的子集
 */
function merge1(sourceobj, targetobj) {
    const result = i ...sourceobj };
    for(let key in targetobj) {
        const itemval = sourceobj[key];
        itemval &&( result[key] = itemval );
    }
    return result;
}
function merge2 (sourceobj,targetobj) {
    return i ...sourceobj, ...targetobj };
}
interface ISourceobj {
    x? : string;
    y? : string;
}
interface ITargetobj {
    x : string;
    y : string;
}
type IMerge = (sourceobj: ISourceobj,targetobj: ITargetobj) => ITargetobj;
/**
 *类型实现繁琐:若obj类型较为复杂,则声明source和target便需要大量重复2遍
 *容易出错:若target增加/i减少key,则需要source联动去除
 */
interface IMerge {
    <T extends Record<string,any>>( sourceobj: Partial<T>,targetobj: T):T;
}
type IPartial<T extends Record<string,any>> = {
    [P in keyof T]?: T[P];
}
//索引类型:关键字【keyof】,其相当于取值对象中的所有key组成的字符串字面量,如
type IKeys = keyof { a: string; b: number };  // => type IKeys = "a" |"b"
//关键字【in】,其相当于取值字符串字面量中的一种可能,配合泛型P,即表示每个key
//关键字【?】,通过设定对象可选选项,即可自动推导出子集类型

4、函数返回值类型

//实现函数delayCall的类型声明
// delayCall接受一个函数作为入参,其实现延迟1s运行函数
//其返回promise,结果为入参函数的返回结果
function delaycall(func) {
    return new Promise(resolve => {
        setTimeout(( =>{
            const result = func();
            resolve(result);
        },1000);
    });
}
type IDelayca1l = <T extends () => any>(func: T) => ReturnType<T>;
type IReturnType<T extends (...args: any) => any> = T extends (...args: any)=> infer R?R: any
​
//关键字【extends】跟随泛型出现时,表示类型推断,其表达可类比三元表达式
//如T===判断类型?类型A:类型B//关键字【infer】出现在类型推荐中,表示定义类型变量,可以用于指代类型
//如该场景下,将函数的返回值类型作为变量,使用新泛型R表示,使用在类型推荐命中的结果中

四、工程应用

1、Web

TypeScript在Web方面的应用可以配置webpack,提高打包的效率

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

2、Node

ts文件可以使用TSC进行编译成为js文件。

image-20220805160441512.png

  • 1、安装Node与npm
  • 2、配置tsconfig.js文件
  • 3、使用npm安装tsc
  • 4、使用tsc运行编译得到js文件