TypeScript入门(下)|青训营笔记

72 阅读5分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 6 天

上篇文章讲述了TypeScript的发展与基本语法。那么接下来这篇文章将讲述一下TypeScript的高级类型和工程应用。

一、高级类型

联合/交叉类型

交叉类型把几个类型的成员合并,形成一个拥有这几个类型所有成员的新类型。它的使用场景:Mixins、不适合用类来定义。而联合类型与交叉类型类似,都可以拥有多个类型的能力,但区别在于联合类型一次只能一种类型,而交叉类型每次都是多个类型的合并类型。

以下面一个例子为例:

为下面这串代码为书籍列表编写类型。

const bookList = [{
    author: 'xiaoming ',
    type: 'history' ,
    range: 200l-2021,
},{
    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>;

存在类型声明繁琐,存在较多重复的问题。

所以接下来可以使用联合类型和交叉类型来解决。

const bookList = [{
    author: 'xi aoming' ,
    type: 'history ',
    range: 200l-2021,
}, {
    author: 'xiaoli',
    type: 'story' ,
    theme : 'love' ,
}]
type IBookList = Array<{
    author: string;
}&({
    type : 'history';
    range: string;
} | {
    type: 'story ';
    theme: string;
})>

这串代码比较简洁,解决了类型声明繁琐,存在较多重复的问题。

类型保护与类型守卫

类型保护是可执行运行时检查的一种表达式,用于确保该类型在一定的范围内。类型保护可以保证一个字符串是一个字符串,尽管它的值也可以是一个数值。类型守卫是一种TypeScript技术,用于获取变量类型信息,通常使用在条件块语句中。类型守卫具有唯一的属性,可以确保测试的值返回的是布尔值类型。

以下面代码为例介绍一下类型保护与类型守卫。

interface IA { a: 1a1: 2 }
interface IB { b: 1b1: 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);
    }
}
//实现函数reverse
//其可将数组或字符串进行反转
function reverse(target:string|Array<any>) {
/* typof类型保护*/
if (typeof target==='string') {
return target.split('').reverse().join('');
/* instance类型保护*/
if (target instanceof Object) { 
return target.reverse(); 
}
}
//实现函数logBook类型
//函数接受书本类型,并logger出相关特征
function logBook(book: IBookItem) {
//联合类型+类型保护=自动类型推断
if (book.type === 'history') {
console. log( book.range)
} else {
console. log(book. theme);

高级类型

下面介绍几种高级类型。

/**
  * 实现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
//关键字【?】,通过设定对象可选选项,即可自动推导出子集类型

函数返回值类型

当函数有返回值时,根据返回值的类型在相应的函数位置进行静态类型定义即可。返回类型有下面几种:返回数字,返回布尔值,返回字符串,返回对象,返回数组,返回值为underfinde 没有返回值。

以下面一个例子为例介绍一下:

//实现函数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表示,使用在类型推荐命中的结果中

二、工程应用

Web

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

Node

使用TCS编译。

image.png

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

三、总结

通过今天的学习我了解了TypeScript的高级类型和工程应用。知道了联合/交叉类型,类型保护与类型守卫,函数返回类型的概念,掌握了一些高级类型。同样也知道了它在Web以及Node方面的应用。相比于JavaScript我认为它更好的地方就是增加了代码的可读性和可维护性类型 TypeScript非常包容并且Typescript是javascript的超集,.js文件可以直接重命名为.ts。