TypeScript-小结

178 阅读10分钟

1.TypeScript 简介

1.1是什么

  1. TypeScript 简称:TS,是 JavaScript 的超集,简单来说就是:JS 有的 TS 都有
  2. TypeScript属于静态强类型编程语言,JavaScript 属于动态弱类型编程语言
  3. TypeScript = Type + JavaScript(在 JS 基础之上,为 JS 添加了类型支持
  4. TypeScript 是微软开发的开源编程语言,可以在任何运行 JavaScript 的地方运行

1.2相关依赖包与命令

  1. 安装命令:npm i -g typescript,用来编译 TS 代码的包,提供了 tsc 命令,实现了 TS -> JS 的转化

    //终端运行命令--->会生成一个同名的js文件
    tsc hello.js
    
  2. 安装命令: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基础数据类型

  1. string number boolean undefined null

  2. 非严格模式下, undefined 和 null 可以分配给任意数据类型

  3. 新版的typescript中,默认开启了严格模式

  4. 创建自定义类型(type):

    • 语法:type Xxxx = 你的类型
    • 推荐类型名称大写开头,可以先使用,后声明
    //创建方式
    type MyArray=(string|number|boolean)[]
    
    //使用方式
    let list5:MyArray=[1,2,'3',false]
    

2.2引用数据类型

  1. 数组=>语法

    //方式一
    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]
    
  2. 函数=>语法

    // 方式一:分开指定函数类型
    //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( 任意 )
  3. 对象=>语法

    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],
    }
    //键名?:值类型  表示该属性可选可不选
    
  4. 对象里的方法

    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

  1. 作用: 描述对象数据结构, 而且只能描述对象数据类型

  2. 语法: interface IXxxx { 键名: 类型}

  3. 推荐: I开头, 大写字母开头名称, 如IPerson

  4. 特点: 接口可以重名, 重名接口可以自动合并

  5. 与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元组

  1. 元组类型:不仅限制数组长度,且限制每个元素的类型

    //方式一
    const list:[number,(number|string),boolean]=[1,'2',true]
    
    //方式二
    type listType=[number,boolean,(number|string)]
    const arr:listType=[1,false,'g']
    

2.5字面量与联合类型

  1. 简单来说就是将值作为类型,提供一组可选的取值范围,字面量的数据类型可以是任意类型

  2. | :表示联合类型,可通俗理解为逻辑 或

    //方式一
    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枚举

  1. 作用:提供一组可选的值,可分为数字枚举字符串枚举

  2. 语法:enum Xxxx { 键名 = 值 }

  3. 数字枚举特点:可以省略值,默认从0开始递增;也可以设置第一个的值, 从第一个值开始递增

  4. 字符串枚举特点:不能递增,不能省略值

    // 枚举自增 枚举只能是数字或字符,当没有值时,默认第一项为 0,然后递增
    //  /** 入职 */ 这样的注释在使用枚举时 vscode 会提示该注释
    enum STATE{
        /** 入职 */
        ENTRY,
        /** 离职 */
        OUT
    }
    function tFn(STATE:STATE){
        console.log(STATE);
    }
    tFn(STATE.ENTRY)
    tFn(STATE.OUT)
    

tips:字面量与枚举的区别

  • 枚举只能声明字符串和数字,不能声明其他类型;而字面量可以声明任意类型
  • 枚举字符串不会自增,字符串枚举的每个成员必须有初始值

2.7断言 as

  1. 作用: 放在值后面去断言值的类型,表示该值就是此类型

  2. 语法:as 类型

    // as HTMLInputElement 表示拿到的一定是input元素
    let input=document.querySelector('input') as HTMLInputElement
    input.value='111'
    

2.8 typeof操作符

  1. 作用: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什么是泛型

  1. 当输入和输入的类型未确定但又需要保持一定程度的统一时,就用到了泛型<T>

  2. <T>就像是一个类型变量,函数被调用时才捕获具体的类型,方便复用

  3. 可以和任意的数据类型组合,表示不同的类型,如:

    • type Xxx = (list: T[]) => T
    • type Xxx = (list: T[]) => {name : T}
    • type Xxx = (list: T[]) => [T, T]
  4. 应用场景:比如,函数输入的参数类型需要和输出的返回值类型要一致

    // 既不限制输入的类型,又做到了保持输入和输出的类型统一
    function testFn<T>(a:T):T{
        console.log(a);
        return a
    }
    

3.2泛型的同时指定和分开指定

  1. 同时指定和分开指定只是两种不同的写法,在功能的实现上并无差别

    // 泛型分开指定写法
    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泛型约束

  1. 语法: <T extends 约束条件>,这里的约束条件要接收一个类型

  2. 理解: 不要理解为继承, 理解为逻辑且 ,表示 不仅是.., 还是..

    //约束条件可以用 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

  1. 获取数据结构中所有的键名, 组成一个字面量 + 联合类型

  2. 语法:keyof 类型

  3. 注意: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多个泛型变量的使用

  1. 语法: <T, K>(aa: T, bb: K) => [T, K]

  2. 泛型变量间可以添加约束条件,如:<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 泛型接口的应用

  1. 语法: interface IXxx {}

  2. 作用: 描述大量相似的数据结构 ,比如网络请求返回的数据等

    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泛型工具

  1. Partial<类型>,将所有的键,转为可选的类型。

    /*
      作用: 将所有的键, 转为可选的类型
      语法: Partial<类型>
    */
    type MyObj = {
      name?: string;
      age: number;
      gender: string;
      gender1: string;
      gender2: string;
    };
    
    const zs: Partial<MyObj> = {};
    
  2. Readonly<类型>,将所有的键变为只读

    /*
      作用: 将所有的键, 全部变为只读
      语法: Readonly<类型>
      注意:如果只需要某一个键名只读,则在创建该类型时,在该键名前加上readonly即表示只有该项属性只读
    */
    
    type MyConfig = {
      baseUrl: string;
      cdn1: string;
      cdn2: string;
    };
    
    // 将所有的键, 全部变为只读
    const config: Readonly<MyConfig> = {
      baseUrl: 'xxxx',
      cdn1: 'xx',
      cdn2: '1231',
    };
    
    // config.cdn1 = '12312';---->会报错
    
  3. 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: '',
};
  1. 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'
}