前端 - 笔记 - TypeScript - 【安装运行TS、TypeScript常见类型(类型注解、常用基础类型、高级类型)】

一、准备工作

1.1 安装 TS

npm install -g typescript / yarn global add typescript

1.2 检测是否安装成功

  • 能看到版本号就表示安装成功;

tsc -v

1.3 更新 TypeScript 的版本

npm update -g typescript**@latest

1.4 ❌ 运行 TS 文件(不推荐)

运行命令: tsc 文件路径 (有些时候tsc不行,tsc.cmd 文件路径);

会生成对应的js文件, 运行js文件即可;

1.5 ✅ 简化 运行TS 步骤(推荐)

全局安装 ts-node 包:npm i -g ts-node / yarn global add ts-node

使用方式:ts-node 文件路径

解释:ts-node命令在内部偷偷的将TS转换为JS,然后,在运行JS代码,此命令并没有生成一个 JS 文件,只是在内部将TS转换为JS(如果之前有JS文件,修改TS文件并用此命令运行后,JS里的内容还是之前的,并没有同步);

注意

  • 在使用这种方式运行 ts 文件时,可能会报错:
    • error TS2584: Cannot find name 'console'. Do you need to change your target library? Try changing the 'lib' compiler option to include 'dom'.
  • 原因:console不属于 ECMAScript 标准。DOM里面的 console 是浏览器环境下的(是 window 对象里面的),属于浏览器 BOM APINode 里面的 consoleNodeJS 里面的,由 NodeJS 自己定义的API,两者虽然由同样的功能,但是并不是同一个东西;
  • 解决方法:
    • 安装 npm i -D tslib @types/node;
      • 该命令是安装 TypScript 助手的运行库,包含所有 TypeScript 辅助函数;
    • 安装到哪里根据自己定义,你也可以选择安装到全局(将 -D 改成 -g 即可);

1.6 TS 和 JS 的区别

  1. TypeScript 是 JS 的超集,TS 提供了 JS 的 所有功能,并且额外的增加了:类型系统
  2. 所有的JS代码都是TS代码;
  3. JS有类型(number、string、boolean、null、undefined、object、array......),但是 JS不会检查变量的类型是否发生变化。而TS会检查
  4. TypeScript类型系统的主要优势:可以显示标记出代码中的意外行为,从而降低了发生错误的可能性;

二、 类型注解

  • 概念

    • 变量 添加 类型约束 ,使变量 只能被赋值为约定好的类型,同时可以有相关的类型提示;
  • 作用

    • 限制变量能赋值的数据类型并给出提示;
  • 解释

    • 约定了什么类型,就只能给变量赋该类型的值(赋别的类型的值会报错);
  • 语法

    ts 复制代码
    变量: 类型
  • 代码展示:

    tsx 复制代码
    // : number - 就是类型注解
    // 约束变量的类型 - 约束的是什么类型,就只能给这个变量赋该类型的值,否则会报错
    let age: number = 23
    age = 24
    // age = '24' - 报错:不能将类型"string",分配给类型"number"
  • 说明: : number 就是 类型注解,约束变量 age 只能被赋值为 number类型,同时可以有 number类型相关的提示;

三、 常用基础类型

3.1 类型分类

  • 可以将TS中的常用 基础类型 细分为 两类
    • JS已有类型
    • TS新增类型

3.1.1 JS已有类型

  • 基本数据类型

    • numberstringbooleannullundefinedsymbol
    • 特点:简单,完全按照JS中类型的名称来书写;
  • symbol

    • 表示独一无二的值,最大的用法是用来定义对象的唯一属性名;

    • Symbol函数栈不能用 new 命令,因为 Symbol 是原始数据类型,不是函数。可以接受一个字符串作为参数,为新创建的 Symbol 提供描述,用来显示在控制台或者作为字符串的时候使用,便于区分;

      tsx 复制代码
      const a: number = 1;
      const b: string = '1';
      const c: boolean = true;
      const d: undefined = undefined;
      const e: null = null;
      const f: symbol = Symbol('symbol');
  • 引用数据类型

    • object(数组、对象、函数、......);
    • 特点 :对象类型,在TS中更加细化,每个具体的对象都有自己的类型语法
    tsx 复制代码
    // 数组类型的两种写法:(推荐第一种写法)
    
    // ✅ 数值类型数组 - 因为已经约束为number类型,所以在该数组中只能出现number类型,不能出现其他类型
    const arr: number[] = [1, 2];
    
    // ❌ 字符串类型数组 - 不推荐
    const arr1: Array<number> = [1, 2];
    
    const obj: {
        name: string
        age: number
        sayHi(): void
        // 参数可传可不传
        greet: (type?: string) => void
    } = {
        name: '奥特曼',
        age: 12,
        sayHi: () => {},
        greet: (type) => type
    };
    obj.greet();
    
    const timeObj: {
        startTime: number
        endTime: Date
    } = {
        startTime: new Date().getTime(),
        endTime: new Date()
    };

3.1.2 TS新增类型

  • 联合类型(|);
  • 自定义类型(类型别名)(type);
  • 接口(interface);
  • 元组(特殊的数组);
  • 字面量类型;
  • 枚举(enum);
  • void(空);
  • 泛型;
  • any(任何类型)等;

3.1.3 ❗ 注意

  • 简单类型类型名 只能是 小写

  • 有时候发现,类型名首字母大写,也不会报错,但是所表达的意思就不一样了;

    • 小写:表示该变量的值是 string 类型;
    • 大写:表示该变量是一个实例对象;
    • 为什么大写的 String 也可以?
      • 像数字、字符串等,在 JS 内部有个 内部包装类 ,当我们把 字符串当对象使用的时候,在 js 内部会帮我们自动进行包装;
    ts 复制代码
    // 类型名小写
    // 约束变量的str的类型是 string 类型
    let str: string = '13';
    
    // 类型名大写
    // 此处的意思是 str1 表示是个 实例对象,是 String 的 实例对象
    let str1: String = '123';
    // 这种才是 大写 String 的正确赋值方法
    let str2: String = new String('123');

3.2 数组类型注解

  • 数组 的 类型注解 有 两种方式:

    • ✅ 方式一:
    ts 复制代码
    // 字符串类型的数组
    const arr: string[] = ['1'];
    
    // 数字类型的数组
    const arr1: number[] = [1];
    
    // 对象类型的数组
    const objArr: object[] = []
    • ❌ 方式二(泛型写法):
    ts 复制代码
    // 数字类型的数组
    const arr; Array<number> = [1];
    
    // 字符串类型的数组
    const str: Array<string> = ['1'];

3.3 联合类型

联合类型(|):由 两个多个 其他类型 组成的 类型 ,表示可以是 这些类型 中的 任意一种

  • 代码展示:

    tsx 复制代码
    // 联合类型 - |
    // 添加小括号:首先是数组,其次,这个数组中元素的类型
    let arr: (number | string | boolean | object)[] = [1, true, 'a', {name: '哈哈'}]
    
    // ❗ 注意区分
    
    // 不添加小括号:test既可以是数字 也可以是 字符串型的数组
    let test: number | string[] = 1
    let test1: number | string[] = ['a']
  • 🔺 注意

    • 添加小括号
      • 可以是 许多类型 中的 任意一种
      • 也可是 多种类型 同时出现
    • 不添加小括号
      • const a = string | number[] = 1;
      • const a = string | number[] = ['1', '2'];
      • 既可以是 string类型,也可以是 number类型的数组;
      • 多种类型 只能同时 出现一个

3.4 类型别名(自定义类型)

3.4.1 基本使用

  • 类型别名

    • 自定义类型
    • 为任意类型起别名;
  • 使用场景

    • 当同一类型(比较复杂的类型)被多次使用时,可以通过类型别名,简化该类型的使用;

    解释

    1. 使用 type 关键字类创建类型别名;
    2. 类型别名可以是任意合法的变量名称;
    3. 创建类型别名后,直接 使用该类型别名作为变量的类型注解 即可;
  • 语法

    ts 复制代码
    type 类型别名 = { 定义类型 };
  • 注意

    • 类型别名的命名采用规范的 大驼峰格式
    • 类型别名 不能 重复定义
  • 代码展示:

tsx 复制代码
/**
 * 使用 type 关键字来创建类型别名
 * 类型别名可以是任意合法的变量名称
 * 创建类型别名后,直接 使用该类型别名作为变量的类型注解 即可
 */

type CustomArray = (number | string)[]
let arr1: CustomArray = [1, 2, 'a']
let arr2: CustomArray = ['x', 'y', 'z', 6, 7]

3.4.2 type + 交叉类型模拟继承

  • 类型别名 配合 交叉类型& )可以 模拟 继承,同样可以实现类型复用;

  • 代码展示:

    ts 复制代码
    // 父接口
    type GoodsType = {
        id: string;
        price: number;
    }
    
    // 子接口继承
    type DIsGoodsType = GoodsType & {
        disPrice: number;
    }

3.5 函数类型

  • 函数类型 :

    • 实际上指的是 函数 参数返回值 的类型;
  • 为函数指定类型的有两种方式:

    1. 单独指定参数、返回值的类型

      ts 复制代码
      // 单独指定参数和返回值类型 - 声明式函数 + 函数表达式
      function add0(a: number, b: number): number {
        return a + b;
      }
      // 设置参数默认值
      function add(a: number = 0, b: number = 0): number {
        return a + b;
      }
      
      const add1 = (a: number, b: number): number => a + b;
      // 设置参数默认值
      const add2 = (a: number = 1, b: number = 1): number => a + b;
    2. 同时指定参数、返回值的类型 :(❗只适用于函数表达式

      ts 复制代码
      // 同时给 参数 和 返回值 指定类型
      // 同时指定参数和返回值类型 - 只适用于 函数表达式
      const sub: (a: number, b: number) => number = (a, b) => a - b;
      // 设置参数默认值
      const sub1: (a: number, b: number) => number = (a = 0, b = 0) => a - b;
  • 🔺注意

    • 如果 函数 没有 返回值 ,那么,函数 返回值 类型为:void
    tsx 复制代码
    // 如果函数没有返回值,那么,函数返回值的类型为void
    function add(name: string): void {
        console.log(name);
    }
    add('小Q');
    • 可选参数
      • 在 可传 可不传 的 参数名称 后面 添加 ?
      • 注意
        • 可选参数 只能出现参数列表最后,也就是说可选参数后面不能再出现必选参数;

3.6 对象类型

  • JS 中的 对象 是由 属性方法 构成 的;
  • TS对象类型 就是在 描述对象 结构(由什么类型的属性和方法);
  • 注意
    • 直接使用 {} 来描述对象结构;
      • 属性 采用 属性名:类型 的形式;
      • 方法 采用 方法名(): 返回值类型 的形式;
    • 如果 方法参数 ,就在 方法名 后面的 小括号指定参数类型 (比如:greet(name: string): void);
    • 一行代码指定对象的多个属性类型 时,使用 ; 来分隔
      • 如果 一行代码只指定一个属性类型 (通过换行来分隔多个属性类型),可以去掉 ;
      • 方法的类型 也可以使用 箭头函数形式
  • 对象类型的写法:
tsx 复制代码
// ❌
let person: {name: string; age: number; sayHi(): void; greet?:(str: string) => void} = {
    name: '邵秋华',
    age: 23,
    sayHi() {},
    greet(str) {}
}

// 和上面的写法意义是一样的,更推荐下面这种,写起来方便很多
// ✅
let person: {
    name: string
    age: number
    sayHi(): void
    greet?:(str: string) => void
} = {
    name: '邵秋华',
    age: 23,
    sayHi() {},
    greet(str) {}
}

3.6.1 对象可选属性

  • 可选属性的语法与函数可选参数的语法一致,都是用 ? 来表示;

  • 代码展示:

    tsx 复制代码
    function myAxios(config: {url: string; method?: string}): void {
        console.log(config);
    }
    const myAxios1: (config: {url: string; method?: string}) => void = (config) => {
        console.log(config);
    }
    
    myAxios({
        url: '哈哈嘻嘻',
        method: 'POST'
    })
    
    myAxios1({
        url: '嘻嘻哈哈'
    })

3.7 接口

  • 当一个 对象类型多次使用 的时候,一般会使用 接口(interface) 来描述 对象类型,达到复用的目的;

  • 作用

    • TS 中使用 interface 接口来描述对象的数据类型(常用于给对象的属性和方法添加类型约束);
  • 解决了什么问题 :

    • 类型的复用问题;
  • 注意

    • 使用 interface 关键字来声明接口;

    • 接口名称,可以是任意合法的变量名称;

    • 声明接口后,直接使用 接口名称 作为变量的类型;

    • 因为每一行只有一个属性类型,因此,属性类型后面没有 ;

    • 一般很少使用 object,基本都是使用 interface 去定义对象,更加准确;

    • interface 接口类型实际限制的是 字段名字段的类型

    • interfacee 是可以重名的;

      • 第一个接口后面的接口就相当于给第一个接口增加类型;
      ts 复制代码
      interface A {
          msg: string;
          status: number
      }
      
      interface A {
          code: number
      }
      
      // 现在的 A 就等于下面这样
      interafce A {
          msg: string;
          status: number;
          code: number
      }
  • 代码展示:

    tsx 复制代码
    // 定义接口
    interface IPerson {
        name: string
        age: number
        work: string
        city: string
        sayHi(): void
        greet: (str: string) => void
    }
    
    // 使用接口
    const obj: IPerson = {
        name: '邵秋华',
        age: 24,
        work: '中级Web前端开发工程师',
        city: '武汉',
        sayHi() {},
        greet(str) {}
    }
    
    console.log(obj);
  • 接口练习:

    • 下面 interface 中的 分号 可以 省略;
    ts 复制代码
    // 后端返回到数据
    /* {
      message: [
        {
          image_src: "",
          open_type: "",
          goods_id: 122,
          navigator_url: ""
        }
      ],
      meta: {
        msg: "",
        status: 200
      }
    } */
    
    // 方式一 ✅:使用多个 interface
    interface BannerInfo {
        image_src: string;
        open_type: string;
        goods_id: number;
        navigator_url: string;
    }
    
    interface ResInfo {
        msg: string;
        status: number;
    }
    
    interface BannerRes {
        message: BannerInfo[];
        meta: ResInfo
    }
    
    // 方式二 ❌:纯手写
    interface BannerRes {
        message: Array<{
            image_src: string;
            open_type: string;
            goods_id: number;
            navigator_url: string;
        }>;
        meta: {
            msg: string;
            status: number
        }
    }
    
    interface BannerRes {
        message: {
            image_src: string;
            open_type: string;
            goods_id: number;
            navigator_url: string;
        }[];
        meta: {
            msg: string;
            status: number
        }
    }

3.7.1 接口的继承

  • 如果两个接口之间有相同的属性或方法,可以将公共的属性或方法抽出来,通过继承来实现复用;

  • 接口的继承使用过关键字 extends

  • 代码展示:

    tsx 复制代码
    interface Meta {
      msg: string;
      status: number;
    }
    
    // 接口 Res1 继承 Meta
    interface Res1 extends Meta {
      success: boolean
    }
    
    const xiHa: Res1 = {
      success: true,
      msg: "",
      status: 200
    }

解释

  • 使用 extends(继承) 关键字实现了接口 Res1 继承 Meta;
  • 继承后,Res1 就有了 Meta 的所有属性和方法;

3.7.2 接口的可选字段

  • 概念

    • 通过 ? 对属性进行可选标注,赋值的时候 该属性可以缺失,如果有值必须保证类型满足要求;
  • 代码展示:

    ts 复制代码
    interface Res {
        msg: string;
        status: number;
        code: number;
        success?: boolean
    }
    
    const resInfo: Res = {
        msg: "",
        status: 200,
        code: 200
    }

3.7.3 接口和类型别名的对比

  • 相同点
    • 都可以 给 对象 指定类型
    • 都能实现继承的效果:
      • interface 使用 extends
      • type 配合 交叉类型 模拟 继承
  • 不同点
    • 接口
      • 只能 为 对象 指定类型
      • 同名的接口会合并(属性取并集,不能出现类型冲突);
    • 类型别名
      • 可以为 任意类型 指定 别名
      • 不能声明同名的 type(会报错);

3.8 元组

  • 元组 :元组类型是另一种类型的数组,它 确切 地 知道 包含 多少 个 元素 ,以及 特定元素 对应 的 类型

    tsx 复制代码
    // 只能写两个元素,并且都是 number类型的
    let position: [number, number] = [256, 134]

3.9 类型推断

  • 发生类型推断的2种常见场景:
    • 声明变量并初始化;
    • 决定函数返回值时;
  • 这两种情况下,类型注解可以省略不写;

3.10 类型断言

  • 作用

    • 有些时候开发者比TS本身更清楚当前的类型是什么,可以使用断言(as)让类型更加精确和具体;
  • 使用 as 关键字实现 类型断言

  • 关键字 as 后面的类型是一个 更加具体的类型HTMLAnchorElementHTMLElement的子类型);

  • 通过类型断言,aLink的类型变得更加具体,这样就可以访问a标签特有的属性或方法了

    tsx 复制代码
    const aLink = document.getElementById('link') as HTMLAnchorElement
  • ❌ 另一种语法 <>

    tsx 复制代码
    const aLink = <HTMLAnchorElement>document.getElemetById('link')
  • 代码展示:

    ts 复制代码
    function fix(a: number | string, b: number | string): number | string | null {
      if (typeof(a) === "number" && typeof(b) === "number") return a + b;
      if (typeof(a) === "string" && typeof(b) === "string") return a + b;
      return null;
    }
    • 不进行类型断言:
      • 提示的是 string 和 number 共有的方法或属性;
    • res 断言为 number:
      • 提示的都是和 number 相关的方法或属性;
    • res 断言为 string:
      • 提示的都是和 string 相关的方法或属性;
    • res 断言为 null:
      • null没有属性和方法,所以什么都不提示
  • 拓展

    • 查看类型 console.dir(xxx)最后面就有类型([[Prototype]]: 类型);

3.11 字面量类型

  • 字面量类型通常和联合类型(|)一起使用;
  • 字面量类型与常规类型相比的优势是什么?
    • 类型更加精确;
    • 提供精确的可选值范围;
ts 复制代码
// 字面量类型
type Gender = 1 | 2;

// 只能给 gender 赋值为 1 | 2
const gender: Gender = 1;
tsx 复制代码
// str 是用 let 声明的,是一个变量,它的值可以是任意字符串,所以类型为:string
let str = '123'

// hello 是用 const 声明的,是一个常量,它的值不能变化只能是'hello ts',所以类型为:'hello ts'
const hello = 'hello ts'

/**
 * obj 也是用 const 声明的,它的值也不能变化,所以类型为:
 * obj: {
 *  name: string
 *  age: number
 * }
 */
const obj = {
  name: '邵秋华',
  age: 23
}

/**
 * 同理,arr的类型为:
 * arr: (number | string)[]
 */
const arr = [1, 2, '3']

/**
 * 除字符串外,任意的JS字面量(对象、数字、数组......)都可以作为类型使用
 */
  • 使用模式
    • 字面量类型 配合 联合类型 一起使用;
  • 使用场景
    • 用来 表示一组明确的可选值列表
  • 优势
    • 相比于 string 类型,使用字面量类型更加精确、严谨;
tsx 复制代码
// 在贪吃蛇游戏中,游戏的方向的可选值只能是上、下、左、右中的任意一个
function changeDirection(direction: 'up' | 'down' | 'left' | 'right') {
  console.log(direction)
}
changeDirection('left')
/**
 * 解释:参数 direction 的值只能是 up/down/left/right 中的任意一个
 * 优势:相比于 string 类型,使用字面量类型更加精确、严谨
 */

3.12 枚举

  • 枚举的功能类似于 字面量类型 + 联合类型 组合的功能,也可以 表示一组明确的可选值
  • 枚举
    • 定义一组 命名常量
    • 使用 enum 关键字定义枚举;
    • 他描述一个值,该值可以是这些命名常量中的一个;
tsx 复制代码
enum Direction { Up, Down, Left, Right }
function changeDirection(direction: Direction) {
  console.log(direction);
}
  • 🔺 注意:
    • 使用 enum 关键字定义枚举;
    • 约定枚举名称、枚举中的值以 大写字母开头
    • 枚举中的多个值之间通过 ,(逗号)分隔;
    • 定义好枚举后,直接使用 枚举名称 作为 类型注解
  • 访问枚举成员
    • 类似于JS中的对象,直接通过 . 点语法访问枚举成员;

3.12.1 数字枚举

  • 枚举成员是有值的,默认为:从0开始递增的数值
  • 数字枚举:枚举成员 为 数字 的 枚举;
  • 当然,也可以给枚举中的成员初始化值;
tsx 复制代码
// enum Direction { Up, Down, Left, Right }
// function changeDirection(direction: Direction) {
//   console.log(direction);
// }

// enum Direction {
//   Up,
//   Down,
//   Left,
//   Right
// }

// Down = 11, Left = 12, Right = 13
// enum Direction {
//   Up = 10,
//   Down,
//   Left,
//   Right
// }

enum Direction {
  Up = 2,
  Down = 4,
  Left = 8,
  Right = 16
}

function changeDirection(direction: Direction) {
  console.log(direction);
}

// 访问 枚举成员
changeDirection(Direction.Up);
changeDirection(Direction.Down);
changeDirection(Direction.Left);
changeDirection(Direction.Right);

3.12.2 字符串枚举

  • 字符串枚举枚举成员字符串
  • 🔺 注意
    • 字符串枚举没有自增长行为,因此,字符串枚举 的 每个成员 必须有 初始值
tsx 复制代码
// 字符串枚举
enum Direction {
  Up = 'UP',
  Down = 'Down',
  Left = 'Left',
  Right = 'Right'
}

3.12.3 枚举的特点及原理

  • 枚举是TS为数不多的非JavaScript类型级扩展(不仅仅是类型)的特征之一
    • 其他类型仅仅被当作类型,而枚举不仅用做类型,还提供值(枚举成员都是有值的)
    • 也就是说,其他的类型都会在编译为JS代码时自动移除,但是,枚举类型会被编译为JS代码
    • 说明:
      • 枚举与前面讲到的字面量类型+联合类型组合的功能类似,都用来表示一组明确的可选值列表
      • 一般情况下,推荐使用字面量类型+联合类型组合的方式,因为相比枚举,这种方式更加直观、简洁、高效

3.13 ❌ any 类型

  • 不推荐使用 any类型;
  • 作用
    • 变量被注解为 any 类型之后,TS会忽略类型检查,错误的类型赋值不会报错,也不会有任何提示;
  • 隐式具有any类型的情况:
    • 声明变量不提供类型也不提供默认值;
    • 函数参数不加类型;
  • 注意
    • any 使用的越多,程序可能出现的漏洞越多,因此不推荐使用 any类型,尽量避免;

3.14 泛型(Generics)

  • 概念:
    • 是指在定义接口、函数等类型的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性,使用泛型可以复用类型并且让类型更加灵活;

3.14.1 泛型接口、泛型别名

  • 语法

    • 泛型接口:
      • 在接口类型的名称后面使用 <T> 既声明一个泛型参数,接口里面的其他成员都能使用该参数的类型;
    • 泛型别名:
      • 在类型别名 type 的后面使用 <T> 即可声明一个泛型参数,接口里的其他成员都能使用该参数的类型;
    ts 复制代码
    // 泛型接口
    ✅ interface 类型名称<T> {}
    
    // 泛型别名
    ❌ type 类型名称<T> = xxx
    • 一般泛型名,是一个字母,大写;
  • 通用思路

    • 找到 可变的类型部分 通过泛型 <T> 抽象为泛型参数(定义参数);
    • 再使用泛型的时候,把 具体类型传入到泛型参数位置(传参);
  • 注意

    • 泛型参数可以有多个;
  • 代码展示:

    ts 复制代码
    // 定义泛型接口
    interface ResData<T> {
      code: number;
      msg: string;
      data: T;
    }
    
    // 定义具体类型
    interface User {
      name: string;
      age: number;
      gender: string;
    }
    type UserInfo = ResData<User[]>;
    // 使用泛型并传入具体类型
    // let userData: UserInfo = {
    let userData: ResData<User[]> = {
      code: 200,
      msg: "success",
      data: [
        {
          name: "小Q",
          age: 24,
          gender: "女"
        }
      ]
    };
    
    // 定义具体类型
    interface Goods {
      id: number;
      goods_name: string;
      price: number;
      url: string;
    }
    type GoodInfo = ResData<Goods>;
    // 使用泛型并传入具体类型
    // let goodsData: GoodsInfo = {
    let goodsData: ResData<Goods> = {
      code: 200,
      msg: "success",
      data: {
        id: 123,
        goods_name: "shuiGuo",
        price: 12,
        url: "www.baidu.com"
      }
    };

3.14.2 泛型函数

  • 语法

    • 函数名称 后面使用 <T> 即可声明一个泛型参数,整个函数中(参数、返回值、函数体、变量)都可以使用该参数的泛型;
    ts 复制代码
    function fn<T>() {}
  • 代码展示:

    ts 复制代码
    // 需求:设置一个函数 creatArray,它可以创建一个指定长度的数组,同时将每一项都填充一个默认值(多种类型)
    function createArray<T>(length: number, defVal: T): T[] {
      const arr = [];
      for (let i = 0; i < length; i++) {
        arr[i] = defVal;
      }
      return arr;
    }
    
    console.log(createArray<number>(5, 100));

3.14.3 泛型约束

  • 作用

    • 泛型的特点就是灵活不确定,有些时候泛型函数的内部需要 访问一些特定类型的数据才有的属性,此时会有类型错误,需要通过泛型约束解决;
  • 使用关键字 extends 实现泛型约束;

  • 代码展示:

    ts 复制代码
    // 泛型约束
    interface lengthObj {
      length: number;
    }
    
    function logLen<T extends lengthObj>(obj: T) {
      console.log(obj.length);
    }
    
    // 传参的时候,必须满足 lengthObj 类型
    logLen<lengthObj>({ length: 8 });
    logLen<lengthObj>([1]);
    logLen<lengthObj>("hello ts");
    logLen<lengthObj>(100);  //  报错:类型 number 的参数不能赋值给 lengthObj 的参数

3.15 typeof 运算符

  • TS中的 typeof 操作符:可以在类型上下文中引用变量或属性的类型(类型查询)
  • 使用场景:根据已有变量的值,获取该值的类型,来简化类型书写
tsx 复制代码

说明:

  • 使用 typeof 操作符来获取变量p的类型,结果与第一种(对象字面量形式的类型)相同
  • typeof 出现在 类型注解的位置 (参数名称的冒号后面 ) 所处的环境就在类型上下文(区别于JS代码)
  • 注意: typeof只能用来查询 变量或属性的类型,无法查询其他形式的类型(比如:函数调用的类型)
相关推荐
向前看-27 分钟前
验证码机制
前端·后端
燃先生._.1 小时前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js
高山我梦口香糖2 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
m0_748235242 小时前
前端实现获取后端返回的文件流并下载
前端·状态模式
m0_748240253 小时前
前端如何检测用户登录状态是否过期
前端
black^sugar3 小时前
纯前端实现更新检测
开发语言·前端·javascript
寻找沙漠的人4 小时前
前端知识补充—CSS
前端·css
GISer_Jing4 小时前
2025前端面试热门题目——计算机网络篇
前端·计算机网络·面试
m0_748245524 小时前
吉利前端、AI面试
前端·面试·职场和发展