1.TypeScript 简介
1.1是什么
TypeScript简称:TS,是 JavaScript 的超集,简单来说就是:JS 有的 TS 都有- TypeScript属于静态强类型编程语言,JavaScript 属于动态弱类型编程语言
- TypeScript =
Type+ JavaScript(在 JS 基础之上,为 JS 添加了类型支持) - TypeScript 是微软开发的开源编程语言,可以在任何运行 JavaScript 的地方运行
1.2相关依赖包与命令
-
安装命令:
npm i -g typescript,用来编译 TS 代码的包,提供了tsc命令,实现了 TS -> JS 的转化//终端运行命令--->会生成一个同名的js文件 tsc hello.js -
安装命令:
npm i -g ts-node/npm i -g ts-node@8.5.4(稳定版),用于在Node 环境运行 JS 代码//终端运行命令--->ts文件会直接在node环境下执行,不会生成js文件 ts-node hello.ts
2.TS常用类型
2.1基础数据类型
-
string number boolean undefined null
-
非严格模式下, undefined 和 null 可以分配给任意数据类型
-
新版的typescript中,默认开启了严格模式
-
创建自定义类型(type):
- 语法:type Xxxx = 你的类型
- 推荐类型名称大写开头,可以先使用,后声明
//创建方式 type MyArray=(string|number|boolean)[] //使用方式 let list5:MyArray=[1,2,'3',false]
2.2引用数据类型
-
数组=>语法
//方式一 let list2:string[]=['1'] let list3:(number|string)[]=['1',2] let list4:(number|boolean|null)[]=[1,true,null] //方式二 type MyArray=(string|number|boolean)[] let list5:MyArray=[1,2,'3',false] -
函数=>语法
// 方式一:分开指定函数类型 //function 函数名(参数1:值类型,参数2:值类型):返回值类型 function testFn(a:number,b:number):number{ return a+b } testFn(1,2) const teFn2:(a:string,b:number)=>void=(a,b)=>{} teFn2('china',666) //方式二:同时指定函数类型,同时指定只能写给表达式函数 type MyAddType=(a:number,b:number)=>number const addFn:MyAddType=(a,b)=>{ return a+b } addFn(5,8)- 给参数后面加上 ? 即表示参数可传可不传 ,可选参数必须放在所有必选参数的后面
- 关于返回值的类型:void(无返回值)/ undefined(此时必须返回一个undefined)/ any( 任意 )
-
对象=>语法
type MyObj={ article_id: string; category_id: string; tag_ids?: number[]; visible_level?: number; } const obj:MyObj={ article_id: '字符', category_id: 'chuan', tag_ids?: [1,2], } //键名?:值类型 表示该属性可选可不选 -
对象里的方法
type MyObj={ name:string, //参数?:类型 表示该参数可不传 //方式一 方法名(参数1:值类型,参数2:值类型):返回值类型 SayHi(a:string,b?:number):void, //方式二 方法名:(参数1:值类型,参数2:值类型)=>返回值类型 SayHello:(a:string,b:number)=>boolean } const obj:MyObj={ name:'123', SayHi(a,b) { console.log(a); }, SayHello:(a,b)=>{ return Boolean(a) } } obj.SayHi('778')
2.3接口 interface
-
作用: 描述对象数据结构, 而且只能描述对象数据类型
-
语法: interface IXxxx { 键名: 类型}
-
推荐: I开头, 大写字母开头名称, 如IPerson
-
特点: 接口可以重名, 重名接口可以自动合并
-
与type的区别: type可以描述任意数据结构, interface可以继承其它的interface
interface IMyperson { name:string, age:number, sayHi?(a?:string):void } interface IMyperson{ gender:string, } //同名的接口会自动合并 const tobj:IMyperson={ name:'Kuangtu', age:18, sayHi(a){ console.log(a); }, gender:'2' } //当方法定义可选时,建议用短路运算符判断存在再调用 tobj.sayHi&&tobj.sayHi() //interface的继承性 //一个interface可以通过 extends 继承另一interface的类型定义 interface IBlack extends IMyperson{ run():void } const blackObj:IBlack={ name:'', age:1, gender:'', run(){ console.log('函数触发') } }
tips: interface和type的异同
- 相同: 都可以用来描述对象数据接口
- 不同:
- interface只能用来描述对象结构, type可以描述任意数据结构
- interface可以继承其它的interface, 达到复用类型的效果
2.4元组
-
元组类型:不仅限制数组长度,且限制每个元素的类型
//方式一 const list:[number,(number|string),boolean]=[1,'2',true] //方式二 type listType=[number,boolean,(number|string)] const arr:listType=[1,false,'g']
2.5字面量与联合类型
-
简单来说就是将值作为类型,提供一组可选的取值范围,字面量的数据类型可以是任意类型
-
| :表示联合类型,可通俗理解为逻辑 或
//方式一 let aa:'str'|'paobuliao' |'woyizhizai' aa='str' //方式二 type Mycon='str'|'paobuliao' |{name:'张三'} | [1,2] function testFn(a:Mycon){ console.log(a); } testFn("paobuliao")
2.6枚举
-
作用:提供一组可选的值,可分为数字枚举字符串枚举
-
语法:enum Xxxx { 键名 = 值 }
-
数字枚举特点:可以省略值,默认从0开始递增;也可以设置第一个的值, 从第一个值开始递增
-
字符串枚举特点:不能递增,不能省略值
// 枚举自增 枚举只能是数字或字符,当没有值时,默认第一项为 0,然后递增 // /** 入职 */ 这样的注释在使用枚举时 vscode 会提示该注释 enum STATE{ /** 入职 */ ENTRY, /** 离职 */ OUT } function tFn(STATE:STATE){ console.log(STATE); } tFn(STATE.ENTRY) tFn(STATE.OUT)
tips:字面量与枚举的区别
- 枚举只能声明字符串和数字,不能声明其他类型;而字面量可以声明任意类型
- 枚举字符串不会自增,字符串枚举的每个成员必须有初始值
2.7断言 as
-
作用: 放在值后面去断言值的类型,表示该值就是此类型
-
语法:as 类型
// as HTMLInputElement 表示拿到的一定是input元素 let input=document.querySelector('input') as HTMLInputElement input.value='111'
2.8 typeof操作符
-
作用:typeof 可以直接将获取的类型给别的变量
// 数组 const list: string[] = ['zs'] // typeof list 等同于 string[]--->字符串数组 const list1: typeof list = ['ls'] // 对象 interface MyObj { name: string, age?: number } // 初始写法 const obj: MyObj = { name: 'zs' } // 效果和上面代码相同 const obj1: typeof obj = { name: 'ls' } // 函数 function testFn(q:number,b:boolean):string{ console.log(q,b); return 'fanhuizhi' } const Fn2:typeof testFn=function(a,b){ return '78' }
3. 泛型
3.1什么是泛型
-
当输入和输入的类型未确定但又需要保持一定程度的统一时,就用到了泛型
<T> -
<T>就像是一个类型变量,函数被调用时才捕获具体的类型,方便复用 -
可以和任意的数据类型组合,表示不同的类型,如:
- type Xxx = (list: T[]) => T
- type Xxx = (list: T[]) => {name : T}
- type Xxx = (list: T[]) => [T, T]
-
应用场景:比如,函数输入的参数类型需要和输出的返回值类型要一致
// 既不限制输入的类型,又做到了保持输入和输出的类型统一 function testFn<T>(a:T):T{ console.log(a); return a }
3.2泛型的同时指定和分开指定
-
同时指定和分开指定只是两种不同的写法,在功能的实现上并无差别
// 泛型分开指定写法 function testFn<T>(a:T){ console.log(a); return a } testFn<number>(8) testFn<string>('698') // 泛型同时指定写法 type t2=<T>(a:T)=>T const testFn2:t2=(a)=>{ console.log(a); return a } testFn2<number>(8) testFn2<string>('4564') // 泛型也可以捕获数据深层结构的类型 function myfn<T>(a:T[]):T{ return a[0] } const result=myfn([1]) const result1=myfn(['25']) function myfn2<T>(a:{name:T}):T{ return a.name } const res=myfn2({name:'778'}) const res1=myfn2({name:4456}) const res2=myfn2({name:true})
3.3泛型约束
-
语法: <T extends 约束条件>,这里的约束条件要接收一个类型
-
理解: 不要理解为继承, 理解为逻辑且 ,表示 不仅是.., 还是..
//约束条件可以用 interface interface ILength { length: number; } // 也可以用type定义 type MyLength = { length: number; }; //<T extends MyLength> 表示接收的类型T 得是个对象,且含有length属性 function test<T extends MyLength>(aa: T): T { console.log(' -----> ', aa.length); return aa; } //比如 字符串,数组,及含length属性的对象 test('132'); test([]); test({ length: 123 });
3.4关键字keyof
-
获取数据结构中所有的键名, 组成一个字面量 + 联合类型
-
语法:keyof 类型
-
注意:keyof后面不能跟值
const obj = { name: 'zs', des: '狂徒', age: 18, gender: '男', gender1: '男', gender2: '男', gender3: '男', }; function getValueByKey(key: keyof typeof obj) { return obj[key]; } // 需求1: 出现代码提示 // 需求2: 写了不存在的键名, 要报错 getValueByKey('age'); getValueByKey('gender2'); const name1 = getValueByKey('name'); const age = getValueByKey('age');
3.5多个泛型变量的使用
-
语法: <T, K>(aa: T, bb: K) => [T, K]
-
泛型变量间可以添加约束条件,如:<T, K extends keyof T >(aa: T, bb: K) => T[K]
function test<T, K>(aa: T, bb: K): [T, K] { return [aa, bb]; } const result1 = test(1, '2'); const result2 = test(false, { name: 'zs' });
3.6 泛型接口的应用
-
语法: interface IXxx {}
-
作用: 描述大量相似的数据结构 ,比如网络请求返回的数据等
interface IResponse<T> { success: boolean; message: string; code: number; data: T; } //表示使用了泛型变量T的属性的值必须为此类型:{ rows: string[]; total: number } const userListData: IResponse<{ rows: string[]; total: number }> = { success: true, message: '成功', code: 200, data: { rows: ['1'], total: 100, }, }; const roleListData: IResponse<{ list: string[] }> = { success: true, message: '成功', code: 200, data: {list:['元素1','元素1']}, };
3.7泛型工具
-
Partial<类型>,将所有的键,转为可选的类型。
/* 作用: 将所有的键, 转为可选的类型 语法: Partial<类型> */ type MyObj = { name?: string; age: number; gender: string; gender1: string; gender2: string; }; const zs: Partial<MyObj> = {}; -
Readonly<类型>,将所有的键变为只读
/* 作用: 将所有的键, 全部变为只读 语法: Readonly<类型> 注意:如果只需要某一个键名只读,则在创建该类型时,在该键名前加上readonly即表示只有该项属性只读 */ type MyConfig = { baseUrl: string; cdn1: string; cdn2: string; }; // 将所有的键, 全部变为只读 const config: Readonly<MyConfig> = { baseUrl: 'xxxx', cdn1: 'xx', cdn2: '1231', }; // config.cdn1 = '12312';---->会报错 -
Pick(选择) / Omit (删除)
/*泛型工具-Pick和Omit
作用: Pick 从一个对象类型中, 挑选一部分键, 组成新的对象类型
作用: Omit 从一个对象类型中, 删掉一部分键, 剩下的键组成新的对象类型
语法:
Pick<你的类型, 要挑选出来的键名组成的联合字面类型>
Omit<你的类型, 要删掉的键名组成的联合字面类型>
*/
type MyConfig = {
baseUrl: string;
cdn1: string;
cdn2: string;
};
const config: Pick<MyConfig, 'baseUrl' | 'cdn1'> = {
baseUrl: 'xxx',
cdn1: 'xxx',
};
const config2: Pick<MyConfig, 'cdn2' | 'cdn1'> = {
cdn1: 'xxx',
cdn2: 'yyy',
};
const config3: Omit<MyConfig, 'cdn2' | 'cdn1'> = {
baseUrl: 'xxx',
};
const config4: Omit<MyConfig, 'baseUrl'> = {
cdn1: 'xxx',
cdn2: '',
};
-
ReturnType<typeof 函数名> :获取一个函数的返回值类型
/*泛型工具-ReturnType 作用: 获取一个函数的返回值类型 创建: 当一个函数的返回值类型特别复杂, 又需要复用时 语法: ReturnType<typeof 函数名> */ const obj = { name: 'zs' }; const obj2: typeof obj = { name: 'zs2' }; function test() { return { name: 'zs', age: 12, a: {}, }; } const result: ReturnType<typeof test> = { name: 'sss', age: 100, a: {}, };
3.8索引签名类型
/*索引签名类型
语法: {[键名: 类型]: 值类型}
作用: 使对象可以添加任意属性,属性值可以定死某个类型也可以 any
*/
interface IXxxx {
name: string;
age: number;
// any不能过度使用, 会破坏类型系统
[key: string]: any;
}
const zs: IXxxx = {
name: 'zs',
age: 18,
};
zs.gender = '男';
zs.checked = true;
3.9 映射类型
/*
学习目标:映射类型
作用: 从已有的数据结构中,生成新的数据结构
理解:类似for in 循环, 会将所有的键复制一份
语法: [key in 字面量联合]
*/
type MyConfig = {
baseUrl: string;
cdn: string;
};
type MyReadonly<T> = {
readonly [key in keyof T]: T[key];
// 类似for in 循环, 会将所有的键复制一份
//T[key]可以将值得类型一并复制过来
};
const config: MyReadonly<MyConfig> = {
baseUrl: 'xxx',
cdn: 'yy',
};
// 此时
// config.baseUrl = 'zxzx';
// config.cdn = 'zxzx';
3.10 索引访问类型
/*索引访问类型
语法: 类型[键名]
作用: 查询某个键对应值的类型
*/
type Person = {
name: string;
age: number;
gender: '男' | '女';
};
const name1: Person['name'] = 'zs';
const age: Person['age'] = 18;
const nameOrAge: Person['name' | 'age'] = 19;
// 获取Person里面所有键对应的属性值类型组成的字面量与联合类型
const all: Person[keyof Person] = '123';
3.11简单实现可选与只读
type Mytype={
name:string,
age:number,
gender:'nan'|'nv'
}
// 实现只读
type MyReadonly<T>={
//循环获取所有的键,并加上readonly
readonly [P in keyof T]:T[P]
}
const obj:MyReadonly<Mytype>={
name:'dfs',
age:554,
gender:'nan'
}
// 实现可选
type MyPartial<T>={
//循环获取所有的键,并加上 ? 可选
[key in keyof T]?:T[key]
}
const bojg:MyPartial<Mytype>={
name:'68'
}