TypeScript敲门 (一)| 青训营笔记

80 阅读7分钟

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

Why

JS是动态类型、弱类型

  • 执行阶段才确定类型的匹配 编译发生在执行时(动态)
  • 类型转换(运行字符串和数字相加的时候会进行隐式转换)

TS是静态类型、弱类型

  • 先走编译 编译产物执行(静态)

静态类型

  • 可读性增强:基于语法解析TSDoc, ide增强

  • 可维护性增强:在编译阶段暴露大部分错误

  • 多人合作的大型项目中,获得更好的稳定性和开发效率

TS是JS的超集

  • 包含于兼容所有Js特性,支持共存

  • 支持渐进式引入与升级

基础数据类型

类型的定义

变量名:类型=变量值


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

对象类型

鸭子类型(Duck Typing)

鸭子类型(英语:duck typing)是动态类型的一种风格,是多态(polymorphism)的一种形式。

在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由"当前方法和属性的集合"决定。

可以这样表述:

"当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。"

在鸭子类型中,关注点在于对象的行为能做什么,而不是关注对象所属的类型。

//定义一个类型 ts的对象一般用I+大写字母 用于和普通的类/对象进行区分



const bytedancer:IBytedancer={
	jobId:9382394,
	name:'Lin',
	sex:'man',
	age:20,
	hobby:'sleep'
}

//通过关键词interface进行定义,在interface后面写上类型的名称
//花括号中通过key和类型进行定义
interface IBtedancer{
/*readonly声明只读属性:约束属性不可在对象初始化外赋值*/
 readonly jobld: number;
 name: string;
 sex: 'man''woman'|'other';
 age: number;
/* 可选属性:定义该属性可以不存在*/
 hobby?: string;
/* 任意属性:约束所有对象属性都必须是该属性的子类型*/
//任意值(Any)用来表示允许赋值为任意类型。
 [key: string]: any;

}

函数类型

函数类型声明

对入参和出参进行补充,返回值类型

//(入参):输出参数
function add (x: number, y: number): number{
   return x + y;
}
​
 const mult: (x: number, y: number) => number = (x, y) => x * y;

通过interface定义

interface IMult{
//函数的类型
  (x:number,y:number):number;
}
const mult:IMult=(x,y)=>x*y;
​

函数重载

 /* 对getDate函数进行重载, timestamp为可缺省参数 */
 //?:表示是一个可以缺省的函数参数
 function getDate(type: 'string', timestamp?: string): string;
 function getDate(type: 'date', timestamp?: string): Date;
 function getDate(type: 'string'|'date', timestamp?: string): Date | string{
   const date = new Date(timestamp);
   return type === 'string' ? date. toLocaleString() : date;
 }
 const x = getDate('date'); // x: Date
 const y = getDate('string', '2018-01-10'); // y: string

通过interface简化

 interface IGetDate {
   (type: 'string', timestamp?: string): string;
 (type: 'date', timestamp?: string): Date;
 (type: 'string''date', timestamp?: string): Date string;
 }
​
​
//ts进行类型推断,匿名函数没有进行函数原类型声明,ts把函数自变量类型和igetdate进行匹配
//两个类型匹配不中,这里不可以返回一个或
/ * 不能将类型"(type: any, timestamp: any) => string Date"分配给类型"IGetDate"。
 不能将类型"string|Date"分配给类型"string"
 不能将类型"Date"分配给类型"string"ts(2322)*/
 const getDate2: IGetDate = (type, timestamp)=>{  
 //ts定义了匿名函数,定义了函数自变量,并把自变量赋值给了getdate2,同时给变量约定了类型是igetdate。
//匿名函数定义成getdate,约定了iget
   const date = new Date(timestamp);
   //匿名函数复制给了变量
   return type === 'string' ? date, toLocaleString() : date;
 }
 //更改方法
 (type: 'string', timestamp?: any): string;
​

数组类型

//一般使用第一种/第二种进行数组定义
/* 「类型+方括号」表示*/
 type IArr1 = number [];
/* 泛型表示 */
 type IArr2 = Array<string|number|Record<string, number>>;
/* 元组表示 *
 type IArr3 = [number, number, string, string];
/* 接口表示 *
 interface IArr4{
   [key: number]: any;
 }
​
 const arrl: 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,{数组元素类型 string,等等} , [元组表示]];

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'
/* 泛型*/
 type INumArr = Array<number>
 
  function getRepeatArr(target) {
     return new Array(100).fill(target);
  }
​
 type IGetRepeatArr = (target: any) => any [];
 
/* 泛型=》不预先指定具体的类型,而在使用的时候再指定类型的一种特性 */ 
//函数中使用泛型用<T>,在前面使用尖括号
  type IGetRepeatArrR = <T>(target: T) => T[];
//使用的时候根据传入的函数再定义类型 //通过泛型解决类型不明确
//泛型 一种变量指代
//在后面使用尖括号。尖括号中的内容就是泛型
/*泛型接口& 多泛型*/
 interface IX<T, U> {
   key: T;
 val: U;
 }
/*泛型类*/
 class IMan<T> {
   instance: T;
 }
/* 泛型别名*/
 type ITypeArr<T> = Array<T>;
​
/* 泛型约束:限制泛型必须符合字符串*/
//extends表示类型约束
//函数范型
 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');
​

类型别名&类型断言

/* 通过type关键字定义了IObjArr的别名类型*/
//因为是可复用的,所用type关键字
 type IObjArr = 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>;
}

字符串/数字 字面量

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

高级类型

联合/交叉类型

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

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

 const bookList = [{ author: 'xiaoming',
 type: 'history',
 range: '2001-2021}
,{
   author: 'xiaoli',
   type: 'story'
   theme: 'love',
}]
 type IBookList = Array<{
   author: string;
 })&{
   type: 'history';
  range: string;
 }|{
   type: 'story';
 theme: string;
 }>
​

类型保护与类型守卫

 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. log(arg.b1);
 } 
 }
​

类型改造

类型守卫只有当两个类型完全没有重合点的时候 需要写一个类型守卫

 interface IA {a: 1, al: 2}
 interface IB {b: 1, b1: 2}
 //声明一个类型守卫
/*类型守卫:定义一个函数,它的返回值是一个类型谓词,生效范围为子作用域*/
 function getIsIA(arg: IA | IB): arg is IA {
 //as的类型断言
 //当他存在a的时候,断言她一定是个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);
  }
}