这是我参与「第五届青训营 」伴学笔记创作活动的第 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: 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);
}
}
//实现函数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
- 配置webapack loader相关配置
- 配置tsconfig.js文件
- 运行webpack启动 /打包
- loader处理ts文件时,会进行编译与类型检查
Node
使用TCS编译。
- 安装Node与npm
- 配置tsconfig.js文件
- 使用npm安装tsc
- 使用tsc运行编译得到js文件
三、总结
通过今天的学习我了解了TypeScript的高级类型和工程应用。知道了联合/交叉类型,类型保护与类型守卫,函数返回类型的概念,掌握了一些高级类型。同样也知道了它在Web以及Node方面的应用。相比于JavaScript我认为它更好的地方就是增加了代码的可读性和可维护性类型 TypeScript非常包容并且Typescript是javascript的超集,.js文件可以直接重命名为.ts。