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

139 阅读4分钟

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

👋本文介绍:基本语法(高级类型:联合/交叉类型、类型保护/类型守卫、索引类型keyof、函数返回类型)、工程应用

高级类型

场景1

为书籍列表编写类型

const bookList=[{
  author:'xiaoming', 
  type:'history', 
  range:'2001-2021',
},{
  author:'xiaoli",
  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;联合类型表示一个值可以是几种类型之一
  • 交叉类型:IA & IB;多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性
type IBookList=Array<{
  author:string;
} & ({
  type:'history'; 
  range:string;
} | {
  type:'story';
  theme:string;
})>

场景2

interface IA{a:1,al:2}
interface IB{b:1,b1:2}
​
function log(arg:IA | IB){
/*报错:类型“IA|IB”上不存在属性“a”。类型“IB”上不存在属性“a”。*/
/*结论:访问联合类型时,处于程序安全,仅能访问联合类型中的交集部分*/
if(arg.a){
  console.log(arg.a1)
}else{
  console.1og(arg.b1);
}

🤔如何改造?

类型保护与类型守卫

  • 类型守卫:定义一个函数,它的返回值是一个类型谓词,生效范围为子作用域
interface IA{a:1,al:2}
interface IB{b:1,b1:2}
/*类型守卫:定义一个函数,它的返回值是一个类型谓词,生效范围为子作用域*/
function getIsIA(arg:IA | IB):arg is IA{
  return !!(arg as IA).a;
}
function log2arg:IA | IB){
  if(getIsIA(arg)){
    console.logarg.a1)
  }else{
    console.logarg.b1);
  }
}
  • 类型保护(Type Guards)就是一些表达式,会在运行时检查以确保在某个作用域内的类型。

Snipaste_2022-08-04_13-36-05.png

typeof 类型保护

typeof 类型保护用于判断变量是哪种原始类型。

/*typof 类型保护*/
if(typeof target ==='string'){
return target.split('').reverse().join('');

typeof 类型保护只有两种形式能被识别:

  • typeof val === 'typename'
  • typeof val !== 'typename'

typename 必须为 number、string、boolean 或 symbol 类型。
但是 TypeScript 并不会阻止与其他字符串比较,语言不会把那些表达式识别为类型保护。

instanceof 类型保护

instanceof 类型保护和 typeof 类型保护用法相似,它主要用于判断是否是一个类的对象或继承对象的。

/*通过instance 类型保护实现对数组的判别*/
if(target instanceof object){
return target.reverse();

instanceof 类型保护是通过构造函数来细化类型,其右侧要求是一个构造函数,TypeScript 将细化为:

  1. 此构造函数的 prototype 属性的类型,如果它的类型不为 any
  2. 构造签名所返回类型的联合

案例:自动类型推断

//实现函数logBook类型
//函数接受书本类型,并logger出相关特征
function logBook(book:IBookItem){
//联合类型+类型保护=自动类型推断
if(book.type==='history'){
  console.1og(book.range)
}else{
  console.1og(book.theme);
}

场景3

实现merge函数类型
要求sourceObj必须为targetObj的子集

//两种实现方式
function mergel(sourceobj, targetobj){
  const result={... sourceobj}; 
  for(let key in targetobj){
    const itemval = sourceobj[ key]; 
    itemval&&( result[key]=itemval ); 
  }
    return result; 
}
function merge2(sourceobj, targetobj){
  return {... 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增加/减少key,则需要source联动去除

改进:

Snipaste_2022-08-04_13-56-20.png

索引查询操作符

索引类型的查询操作符 keyof T。
对于任何类型查询操作符,假设 T 是一个类型,那么 keyof T 产生的类型是 T 的属性名称字符串字面量类型构成的联合类型。

interface Person {
  name: string;
  age: number;
  address: string;
}
​
type person = keyof Person; // 'name' | 'age' | 'address'

keyof Person 是完全可以与 'name' | 'age' | 'address' 互相替换的。

场景4

实现函数delayCall的类型声明205
delayCal接受一个函数作为入参,其实现延迟1s运行函数
其返回promise,结果为入参函数的返回结果

function delaycall(func){
  return new Promise(resolve=>{
    setTimeout()=>{
      const result=func(); 
      resolve(result);
      },1000);
    });
}

类型声明实现:函数返回值类型

Snipaste_2022-08-04_14-05-20.png

工程应用

浏览器Web | Node.js

Typescript工程应用——Web

以 webpack 为例

  1. 配置webapack loader相关配置 (把webpack不能识别的文件转化成可以识别的文件,如: ts文件转化为js文件)
  2. 配置tsconfig.js文件
  3. 运行wabpack启动,打包
  4. loader处理ts文件时,会进行编译与类型检查

相关lader

  1. awesome-typescript-loader:www.npmjs.com/package/awe…
  2. babel-loader: www.npmjs.com/package/bab…

Typescript工程应用——Node

Snipaste_2022-08-04_14-18-36.png

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

参考文章

  1. 字节前端青训营PPT
  2. tsejx.github.io/typescript-…