TypeScript快速入门

news/2024/4/28 22:53:37/文章来源:https://blog.csdn.net/qq_40440961/article/details/128931213

TypeScript快速入门

    • 1.TypeScript介绍
      • 1.1.TypeScript为什么要为JS添加类型支持
      • 1.2.TypeScript相比JS优势
    • 2.TypeScript初体验
      • 2.1.安装编译TS的工具包
      • 2.2.编译并运行TS代码
      • 2.3.简化运行TS代码
    • 3.TypeScript常用类型
      • 3.1.类型注解
      • 3.2.常用基础类型
      • 3.3.原始类型 number/string/boolean/null/undefined/symbol
      • 3.4.对象类型(数组)
      • 3.5.类型别名(自定义类型)
      • 3.6.函数类型
        • void类型
        • 可选参数
      • 3.7.对象类型
        • 可选属性
      • 3.8.接口
        • 接口和类型别名对比
        • 接口继承
      • 3.9.元组
      • 3.10.类型推论
      • 3.11.类型断言
      • 3.12.字面量类型
      • 3.13.枚举类型
      • 3.14.any类型
      • 3.15.typeof
    • 4.TypeScript高级类型
      • 4.1. class类
        • class基本使用:
        • 构造函数
        • 继承extends,implement
        • 可见性修饰符public,protected,private
        • 只读修饰符readonly
      • 4.2.类型兼容性
        • 类之间兼容性
        • 接口之间兼容性
        • 函数直接兼容性
      • 4.3.交叉类型(&)
      • 4.4.泛型 和 keyof
        • 泛型
        • 泛型约束
        • 泛型接口
        • 泛型类
        • 泛型工具类型Partial,Readonly,Pick,Record
      • 4.5.索引签名类型 和 索引查询类型
        • 索引签名类型
        • 映射类型
        • 索引查询类型
    • 5.TypeScript类型声明文件
      • TS 的两种文件类型
      • 类型声明文件的使用说明
        • 使用已有的类型声明文件
        • 创建自己的类型声明文件

1.TypeScript介绍

typescript是js的超集,主要学习ts里面的原始类型、字面量类型、数组类型、函数类型、类类型、接口类型、类型别名、联合与交叉类型、枚举类型、泛型等类型元素,以及类型推断、类型断言、类型缩小、类型放大等特性。相较于js更加严谨,编写代码的时候静态类型的校验。
在这里插入图片描述

1.1.TypeScript为什么要为JS添加类型支持

背景:JS的类型系统有“先天缺陷”,JS代码中的大多数错误都是类型错误Uncaught TypeError。
问题:增加了发现和纠正bug的时间,严重影响了开发效率。

在编程语言的动态性方面,TypeScript是静态类型的编程语言,JS是动态类型的编程语言。
静态类型:在编译时进行类型检查;
动态类型:在执行过程中进行类型检查。
代码编译和代码执行顺序:1编译2执行。

对于JS:你需要等到代码实际执行时才发现错误(后期)。
对于TS:在编译代码时(在执行之前)发现错误
并且,通过VSCode等开发工具,TS可以在编写代码时提前发现代码中的错误,减少了找Bug和改Bug的时间。

1.2.TypeScript相比JS优势

  1. 尽早发现错误(在编写代码时),减少找Bug和改Bug的时间。,提高开发效率。
  2. 程序任何位置的代码都有代码提示,可以随时随地提供一种安全感,增强开发体验。
  3. 强大类型系统提高了代码的可维护性,使重构代码变得更容易。
  4. 支持最新的ECMAScript语法,优先体验最新的语法,让您走在前端技术的最前沿。
  5. TS类型推断机制不需要在代码中处处显示注释类型,它允许您在最小化成本的同时享受其优势。

除此之外,随着vue3源码用TS重写,Angular默认支持TS, React和TS完美配合,TypeScript已经成为大中型前端项目的首选编程语言。

2.TypeScript初体验

2.1.安装编译TS的工具包

问题:为什么要安装编译TS的工具包?
回答:Node.js/ 浏览器,只认识JS代码,不认识TS代码。在运行TS代码之前,需要将其转换为JS代码。
在这里插入图片描述

全局安装命令:

npm i -g typescript@4.5.2

typescript包:编译TS代码的包,提供tsc命令转换TS->JS。
验证是否安装成功:tsc-v(查看typescript版本)

tsc -v

2.2.编译并运行TS代码

  1. 创建hello.ts文件(注意TS文件的后缀名为.ts)
  2. 将TS 编译 JS,在终端输入tsc hello.ts命令。(此时,一个同名的JS文件将出现在同级目录中)
tsc hello.ts
  1. 执行JS代码:在终端中输入命令node hello.js
node hello.js

在这里插入图片描述
说明:所有合法的JS代码都是TS代码,有JS基础只需要学习TS类型即可
注意:由TS编译生成的JS文件,代码中就没有类型信息了

2.3.简化运行TS代码

使用ts-node包,直接在node.js中执行代码
安装命令:

npm i -g ts-node 

使用方式:

ts-node hello.ts

3.TypeScript常用类型

3.1.类型注解

let age: number = 24

在这里插入图片描述
说明:代码中 : number就是类型注解
作用:为变量添加约束条件,约定age的类型为number,如果赋值其他类型,就会报错
在这里插入图片描述

3.2.常用基础类型

可以将TS中常用基础类型细分为两类:

  1. JS已有类型
  • 原始类型:number/string/boolean/null/undefined/symbol
  • 对象类型:object(包括数组,对象,函数等)
  1. TS新增类型
  • 联合类型,自定义类型(类型别名),接口,元组,字面量类型,枚举,void,any等

3.3.原始类型 number/string/boolean/null/undefined/symbol

let num: number = 1; // number
let str: string = "2"; // string
let bool: boolean = true; // boolean
let nul:null = null; // null
let undef: undefined = undefined; // undefined
let sy: symbol = Symbol(); // symbol

3.4.对象类型(数组)

对象类型在TS中更加细化,每个具体对象都有自己的类型语法

数组类型的两种写法

let strArr: string[] = ['a', 'b'] // 推荐使用这种
let numArr: Array<number> = [1, 2, 3]

数组中既有number类型,又有string类型

let numOrStrArr: (number | string)[] = [1, 'a']

解释:|(竖线)在TS中叫做联合类型(由两个以上其他类型组成的类型,可以表示这些类型中任意一种)

let age: number | string = 20; // 表示既可以是number,又可以是stringlet arr: (number | string)[] = [1, 3, 5, 'a', 'b'] // 添加小括号表示:首先是数组,数组中可以出现number或stringlet arr1: number | string[] = ['a','b']let arr1: number | string[] = 123 // 不添加小括号表示:可以是number,或者string数组

3.5.类型别名(自定义类型)

类型别名:为任意类型起别名
使用场景:当同一类型被多次使用时,可以通过类型别名,简化该类型的使用
格式:type 别名名称 = 类型定义

type CustomArray = (number | string)[]let arr: CustomArray = [1, 'a']

3.6.函数类型

函数类型实际上之的是:函数参数返回值的类型

方式一:单独指定参数,返回值的类型

function add(num1: number, num2: number): number {return num1 + num2
}const add1 = (num1: number, num2: number): number => {return num1 + num2
}

方式二:同时指定参数,返回值类型

const add2: (num1: number, num2: number) => number = (num1, num2 ) => {return num1 + num2
}

这种形式只适用于函数表达式

void类型

如果函数没有返回值,那么函数返回值类型为:void

function greet(name: string): void {console.log('Hello', name)
}

可选参数

使用函数实现某些功能时,参数可传可不传,这时候就用到可选参数了
语法:在可传可不传的参数名称后面添加?(问号)

function mySlice(start?: number, end?: number): void {console.log('开始:', start, '结束', end)
}

注意:可选参数只能出现在参数列表的最后,也就是说可选参数后面不能出现必选参数

3.7.对象类型

JS中的对象是由属性和方法构成,而TS中对象的类型就是在描述对象的结构(有什么类型的属性和方法)

let gf : { name: string; age: number; sayLove(): void} = {name: 'yj',age: 26,sayLove() {console.log("honey")},
} let gf1 : { name: stringage: numbersayLove(): void
} = {name: 'yj',age: 26,sayLove() {console.log("honey")},
}
  1. 直接使用{}来描述对象结构。采用=属性名:类型=的形式;方法采用方法名():返回值类型的形式
  2. 如果方法有参数,就在方法名后面的小括号中中指定参数类型(比如:greet(name:string):void
  3. 在一行代码中指定对象的多个属性类型时,使用;(分号)来分隔。
  • 如果一行代码只指定一个属性类型(通过换行来分隔多个属性类型),可以去掉;(分号)
  • 方法的类型也可以使用箭头函数的形式(比如:{sayHi:()=>void}

可选属性

对象的属性或方法,也可以是可选的, 此时就用到可选属性了。
比如,我们在使用 axios({…})时, 如果发送GET 请求, method 属性就可以省略。

function myAxios(config: { url: string; method?: string }){  console.log(config)
}

可选属性的语法与函数可选参数的语法一致,都使用? 问号)来表示。

3.8.接口

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

  1. 使用 interface关键字来声明接口
  2. 接口名称(比如,此处的IPerson),可以是任意合法的变量名称
  3. 声明接口后,直接使用接口名称作为变量的类型
  4. 因为每一行只有一个属性类型,因此,属性类型后没有;(分号)
interface IPerson {name: stringage: numbersayHi(): void
}let person: IPerson = {name: 'dsc',age: 24,sayHi() {}
}

接口和类型别名对比

实际上,在大多数的情况下使用接口类型和类型别名的效果等价,但是在某些特定的场景下这两者还是存在很大区别。

  1. 重复定义的接口类型,它的属性会叠加,这个特性使得我们可以极其方便地对全局变量、第三方库的类型做扩展
  2. 如果我们重复定义类型别名,那么就会报错
    在这里插入图片描述

接口继承

如果两个接口之间有相同的属性或方法, 可以将公共的属性或方法抽离出来, 通过继承来实现复用
比如,这两个接口都有x、y两个属性, 重复写两次,可以,但很繁琐。

interface Point2D { x: number; y: number }
interface Point3D { x: number; y: number; z: number }

更好的方式:

interface Point2D { x: number;y:number }
interface Point3D extends Point2D { z: number }

解释:

  1. 使用extends(继承) 关键字实现了接口Point3D继承Point2D。
  2. 继承后,Point3D就有了Point2D的所有属性和方法(此时, Point3D同时有x、y、z三个属性)。

3.9.元组

场景:在地图中,使用经纬度坐标来标记位置信息。
可以使用数组来记录坐标,那么,该数组中只有两个元素,并且这两个元素都是数值类型。

let position: number[] = [39.5427 116.23171]

使用number[]的缺点:不严谨,因为该类型的数组中可以出现任意多个数字。
更好的方式:元组(Tuple) 。
元组类型是另一种类型的数组,它确切地知道包含多少个元素,以及特定索引对应的类型

let position: [ numbernumber] = [39 .5427116.2317] 

解释:

  1. 元组类型可以确切地标记出有多少个元素,以及每个元素的类型。
  2. 该示例中,元素有两个元素,每个元素的类型都是number。

3.10.类型推论

在TS中,某些没有明确指出类型的地方,TS的类型推论机制会帮助提供类型
换句话说:由于类型推论的存在,这些地方,类型注解可以省略不写!
发生类型推论的2种常见场景:

  1. 声明变量并初始化时
  2. 决定函数返回值时。

在这里插入图片描述

注意:这两种情况下,类型注解可以省略不写!
推荐:能省略类型注解的地方就省略(偷懒,充分利用TS类型推论的能力,提升开发效率)。
技巧:如果不知道类型,可以通过鼠标放在变量名称上,利用VSCode的提示来查看类型。

3.11.类型断言

有时候开发人员会比TS更加明确一个值的类型, 此时, 可以使用类型断言来指定更具体的类型。比如,

<a href="http://www.baidu.com/" id="link">百度</a>

在这里插入图片描述

注意: getElementById方法返回值的类型是 HTMLElement,该类型只包含所有标签公共的属性或方法,不包含 a标签 特有的 href 等属性。
因此,这个类型太宽泛(不具体), 无法操作href等 a标签特有的属性或方法。
解决方式:这种情况下就需要使用类型断言指定更加具体的类型

使用类型断言:

解释:

  1. 使用as关键字实现类型断言
  2. 关键字as 后面的类型是一个更加具体的类型 (HTMLAnchorElement是 HTMLElement 的子类型)
  3. 通过类型断言,aLink的类型变得更加具体, 这样就可以访问a标签特有的属性或方法了
    另一种语法,使用<>语法, 这种语法形式不常用知道即可:
    在这里插入图片描述

技巧:在浏览器控制台,通过console.dir() 打印 DOM 元素,在属性列表的最后面, 即可看到该元素的类型。

3.12.字面量类型

思考以下代码, 两个变量的类型分别是什么?

let str1 = 'Hello TS' 
const str2 = Hello TS'

通过TS类型推论机制,可以得到答案:

  1. 变量 str1 的类型为:string
  2. 变量str2的类型为:'Hello TS'

解释:

  1. str1 是一个变量(let), 它的值可以是任意字符串,所以类型为: string
  2. str2 是一个常量(const), 它的值不能变化只能是’Hello TS’,所以, 它的类型为:'Hello TS'

注意:此处的'Hello TS', 就是一个字面量类型。 也就是说某个特定的字符串也可以作为TS 中的类型
除字符串外,任意的JS字面量(比如, 对象、数字等)都可以作为类型使用。

使用模式:字面量类型配合联合类型一起使用
使用场景: `用来表示一组明确的可选值列表``
比如,游戏的方向可选值上下左右中任意一个

function changDirection(direction: 'up' | 'down' | 'left' | 'right') {console.log(direction)
}

相比于string类型,使用字面量类型更加精确,严谨

3.13.枚举类型

枚举的功能类似字面量类型+联合类型组合的功能,也可以表示一组明确的可选值
枚举:定义一组命名常量。它描述一个值,该值可以是这些常量中的一个

enum Direction { Up, Down, Left, Right }enum Direction {Up = 'UP',Down = 'DOWN',Left = 'LEFT',Right = 'RIGHT'
}

枚举的作用在于定义被命名的常量集合,一个默认从 0 开始递增的数字集合,称之为数字枚举。也可以指定值,这里可以指定的值可以是数字或者字符串。

enum Days {Sunday = 1,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday
}
let day = Days.Sunday;

字符串枚举没有自增长行为,因此,字符串枚举的每个成员必须有初始值
在这里插入图片描述

3.14.any类型

原则:不推荐使用any! 这会让TypeScript变为"AnyScript"(失去TS类型保护优势)
因为当值的类型为any时,可以对该值进行任何操作,并且不会有代码提示
在这里插入图片描述
以上代码都不会有任何类型的错误提示,即使存在错误

尽可能避免使用any类型,除非临时使用any来“避免”书写很长,很复杂的类型

其他隐式具有any类型的情况:

  1. 声明变量不提供类型也不提供默认值
  2. 函参数参数不加类型

3.15.typeof

typeof 的主要用途是在类型上下文中获取变量或者属性的类型(类型查询)

// 推断变量的类型
let strA = "2";
type KeyOfType = typeof strA; // string// 反推出对象的类型作为新的类型
let person = {name: '张三',getName(name: string):void {console.log(name);}
}
type Person = typeof person;// 根据已有变量的值,获取该值类型,简化类型书写
let p = { x: 1, y: 2 }
function fornatPoint(point: typeof p) {}

4.TypeScript高级类型

4.1. class类

TypeScript全面支持ES205中引入的class关键字,并为其添加了类型注解和其他语法(比如可见性修饰符)

class基本使用:

在这里插入图片描述

  1. 根据TS中类型推论,可以知道Person类的实例对象p的类型是Person
  2. TS中的class,不仅提供了class的语法功能,也作为一种类型存在

实例属性初始化:
在这里插入图片描述

  1. 声明成员age,类型为number(没有初始值)
  2. 声明成员gender,并设置初始值,此时,可省略类型注解(TS类型推论为string类型)

实例方法:
在这里插入图片描述
方法的类型注解(参数和返回值)与函数用法相同

构造函数

class Person {age: numbergender: stringconstructor(age: number, gender: string) {this.age = agethis.gender = gender}
}

在这里插入图片描述

  1. 成员初始化后,才可以通过this来访问实例成员
  2. 需要为构造函数指定类型注解,否则会被隐式推断为any;构造函数不需要返回值类型

继承extends,implement

class Animal {move() {console.log('move')}
}class Dog extends Animal {bark() {console.log("汪汪汪")}
}const dog = new Dog()
  1. 通过extends关键字实现继承
  2. 子类Dog继承父类Animal,则Dog的实例对象dog就同时具有了父类Animal和子类Dog的所有属性和方法
interface Singable {sing(): void
}class Person implements Singable {sing() {console.log("你我山前没相见山后别相逢")}
}
  1. 通过implements关键字让class实现接口
  2. Person类中必须提供Singable接口中指定的所有方法和属性

可见性修饰符public,protected,private

类成员可见性:可以用TS来控制class的方法或属性对于class外的代码是否可见
可见性修饰符包括:public(公有的),protected(受保护的),private(私有的)
public:公有成员可以被任何地方访问,默认可见性,可以直接省略
在这里插入图片描述
protected:表示受保护的,仅对其声明所在类和子类中(非实例对象)可见,实例不可见
在这里插入图片描述
private:表示私有的,只在当前类可见,对实例对象以及子类也是不可见
在这里插入图片描述

只读修饰符readonly

readonly:表示只读,用来防止在构造函数之外对属性进行赋值
在这里插入图片描述

  1. readonly只能修饰属性,不能修饰方法
  2. 属性后面类型注解如果不加,则类型为字面量类型
  3. 接口或者{}表示的对象类型,也可以使用readonly

4.2.类型兼容性

两种类型系统:1.StructuralType System(结构化类型系统)2 .NominalType System(标明类型系统)
TS 采用的是结构化类型系统,也叫做 ducktyping(鸭子类型),类型检查关注的是值所具有的形状
也就是说,在结构类型系统中,如果两个对象具有相同的形状,则认为它们属于同一类型。

类之间兼容性

在这里插入图片描述

  1. Point 和 Point2D 是两个名称不同的类。

  2. 变量 p 的类型被显示标注为 Point 类型,但是它的值却是 Point2D 的实例,并且没有类型错误。

  3. 因为 TS 是结构化类型系统,只检查 Point 和 Point2D 的结构是否相同(相同,都具有 x 和 y 两个属性,属性类型也相同)。

  4. 但是,如果在 Nominal Type System 中(比如,C#、Java 等),它们是不同的类,类型无法兼容。

在结构化类型系统中,如果两个对象具有相同的形状,则认为它们属于同一类型,这种说法不准确。更准确的说法:对于对象类型来说,y的成员至少与x相同,则x兼容y(成员多的可以赋值给少的)
在这里插入图片描述

接口之间兼容性

接口之间兼容性类似于class,并且class和interface之间也可以兼容
在这里插入图片描述
在这里插入图片描述

函数直接兼容性

函数之间兼容性比较复杂,需要考虑:1参数个数2参数类型3返回值类型

  1. 参数个数,参数多的兼容参数少的
    在这里插入图片描述
    在这里插入图片描述

  2. 参数类型,相同位置的参数类型要相同(原始类型)或兼容(对象类型)
    在这里插入图片描述

  3. 返回值类型,只关注返回值类型本身即可
    在这里插入图片描述
    如果返回值类型是原始类型,此时两个类型要相同
    在这里插入图片描述
    如果返回值类型是对象类型,此时成员多的可以赋值给成员少的

4.3.交叉类型(&)

功能类似于接口继承,用于组合多个类型为一个类型(常用于对象类型)

interface Person { name: string }
interface Contact { phone: string }
type PersonDetail = Person & Contactlet obj: PersonDetail = {name: 'dsc',phone: '176...'
}

交叉类型和接口继承的对比

  • 相同点:都可以实现对象类型的组合
  • 不同点:两种方式实现组合时,对于同名属性间,处理类型冲突的方式不同
    在这里插入图片描述
    以上代码,接口继承会报错(类型不兼容);交叉类型没有错误,可以简单理解为:
    方法重载
fn: (value: string | number) => string

4.4.泛型 和 keyof

泛型

泛型是可以在保证类型安全前提下,让函数等与多种类型一起工作,从而实现复用,常用于:函数、接口、class 中。需求:创建一个 id 函数,传入什么数据就返回该数据本身(也就是说,参数和返回值类型相同)。

function id (value: number): number { return value }

比如,id (10) 调用以上函数就会直接返回 10 本身。但是,该函数只接收数值类型,无法用于其他类型。

为了能让函数能够接受任意类型,可以将参数类型修改为 any。但是,这样就失去了 TS 的类型保护,类型不安全。

function id (value: any): any { return value }

泛型在保证类型安全(不丢失类型信息)的同时,可以让函数等与多种不同的类型一起工作,灵活可复用。实际上,在 C#和 Java 等编程语言中,泛型都是用来实现可复用组件功能的主要工具之一。

  • 创建泛型函数
function id<Type> (value: Type): Type {return value}
  1. 语法:在函数名称的后面添加<>(尖括号),尖括号中添加类型变量,比如此处的 Type。

  2. 类型变量 Type,是一种特殊类型的变量,它处理类型而不是值。

  3. 该类型变量相当于一个类型容器,能够捕获用户提供的类型(具体是什么类型由用户调用该函数时指定)。

  4. 因为 Type 是类型,因此可以将其作为函数参数和返回值的类型,表示参数和返回值具有相同的类型。

  5. 类型变量 Type,可以是任意合法的变量名称。

  • 调用泛型函数
const num = id<number>(10)
const str = id<string>('a')
  1. 语法:在函数名称的后面添加<>(尖括号),尖括号中指定具体的类型,比如,此处的 number。
  2. 当传入类型 number 后,这个类型就会被函数声明时指定的类型变量 Type 捕获到。
  3. 此时,Type 的类型就是 number,所以,函数 id 参数和返回值的类型也都是 number。

同样,如果传入类型 string,函数 id 参数和返回值的类型就都是 string。

这样,通过泛型就做到了让 id 函数与多种不同的类型一起工作,实现了复用的同时保证了类型安全

  • 简化泛型函数调用
let num = id(10)
  1. 在调用泛型函数时,可以省略<类型>来简化泛型函数的调用

  2. 此时,TS 内部会采用一种叫做类型参数推断的机制,来根据传入的实参自动推断出类型变量 Type 的类型。

  3. 比如,传入实参 10,TS 会自动推断出变量 num 的类型 number,并作为 Type 的类型。

推荐:使用这种简化的方式调用泛型函数,使代码更短,更易于阅读。

说明:当编译器无法推断类型或者推断的类型不准确时,就需要显式地传入类型参数。

泛型约束

泛型约束:默认情况下,泛型函数的类型变量 Type 可以代表多个类型,这导致无法访问任何属性。

比如,id (‘a’)调用函数时获取参数的长度:

function id<Type>(value: Type): Type{console.log (value. length)return value
}

解释:Type 可以代表任意类型,无法保证一定存在 length 属性,比如 number 类型就没有 length。

此时,就需要为泛型添加约束来收缩类型(缩窄类型取值范围)。

方式一:指定更加具体的类型

function id<Type>(value: Type[]): Type[] {console.log(value.length)return value
}

方式二:添加约束

interface ILength { length: number }
function id<Type extends ILength>(value: Type): Type {console.log(value.length)return value
}

该约束表示:传入的类型必须具有length属性

泛型的类型变量可以有多个,并且类型变量之间还可以约束(比如,第二个类型变量受第一个类型变量约束)。比如,创建一个函数来获取对象中属性的值:


function getProp<Type, Key extends keyof Type> (obj: Type, key: Key){return obj [key]
}
let person = { name: 'jack', age: 18 } 
getProp (person, 'name')

解释:

  1. 添加了第二个类型变量 Key,两个类型变量之间使用(,)逗号分隔。

  2. Keyof 关键字接收一个对象类型,生成其键名称(可能是字符串或数字)的联合类型。

  3. 本示例中 keyof Type 实际上获取的是 person 对象所有键的联合类型,也就是:‘name’|‘age’。

  4. 类型变量 Key 受 Type 约束,可以理解为:Key 只能是 Type 所有键中的任意一个,或者说只能访问对象中存在的属性。

泛型接口

接口也可以配合泛型来使用,以增加其灵活性,增加其复用性
在这里插入图片描述

  1. 在接口名称的后面添加<类型变量>,那么,这个接口就变成了泛型接口。

  2. 接口的类型变量,对接口中所有其他成员可见,也就是接口中所有成员都可以使用类型变量

  3. 使用泛型接口时,需要显式指定具体的类型(比如,此处的 IdFunc < number>)。

  4. 此时,id 方法的参数和返回值类型都是 number; ids 方法的返回值类型是 number[ ]。

泛型类

class也可以配合泛型来使用
比如,React的class组件的基类Component就是泛型类,不同的组件有不同的props和state
在这里插入图片描述
创建泛型类

class GenericNumber<NumType> {defaultValue: NumTypeadd: (x:NumType, y:NumType) => NumType
}

使用泛型类

const myNum = new GenericNumber<number>()
myNum.defaultValue = 10

泛型工具类型Partial,Readonly,Pick,Record

Partial< Type> 用来构造(创建)一个类型,讲Type的所有属性设置为可选

interface Props {id: stringchildren: number[]
}
type PartialProps = Partial<Props>

构造出来的新类型PartialProps结构和Props相同,但所有属性都变为可选的

Readonly< Type> 用来构造(创建)一个类型,讲Type的所有属性设置为只读

interface Props {id: stringchildren: number[]
}
type PartialProps = Partial<Props>
let props: ReadonlyProps = { id:'1', children: []}
props.id = '2' // 报错,无法分配,因为它是只读

构造出来的新类型PartialProps结构和Props相同,但所有属性都变为只读的

Pick <Type, Keys> 从 Type 中选择一组属性来构造新类型

interface Props {id: string title: stringchildren: number[]
}
type PickProps = Pick<Props, 'id' | 'title'>
  1. Pick 工具类型有两个类型变量:1 表示选择谁的属性 2 表示选择哪几个属性。
  2. 其中第二个类型变量,如果只选择一个则只传入该属性名即可。
  3. 第二个类型变量传入的属性只能是第一个类型变量中存在的属性。
  4. 构造出来的新类型 PickProps,只有 id 和 title 两个属性类型。

Record <Keys, Type> 构造一个对象类型,属性键为Keys,属性类型为Type

type RecordObj = Record<'a' | 'b' | 'c', string[]>
let obj:RecordObj = {a: ['1'],b: ['2'],c: ['3']
}
  1. Record工具类型有两个类型变量:1表示对象有哪些属性2表示对象属性的类型
  2. 构建的新对象类型RecordObj表示:这个对象有三个属性分别为a/b/c,属性值的类型都是string[]

4.5.索引签名类型 和 索引查询类型

索引签名类型

绝大多数情况下,我们都可以在使用对象前就确定对象的结构,并为对象添加准确的类型。

使用场景:当无法确定对象中有哪些属性(或者说对象中可以出现任意多个属性),此时,就用到索引签名类型了。

在这里插入图片描述

  1. 使用[key: string]来约束该接口中允许出现的属性名称。表示只要是 string 类型的属性名称,都可以出现在对象中。

  2. 这样,对象 obj 中就可以出现任意多个属性(比如,a、b等)。

  3. key 只是一个占位符,可以换成任意合法的变量名称。

  4. 隐藏的前置知识:JS 中对象({})的键是 string 类型的
    在这里插入图片描述
    在JS中数组是一类特殊的对象,特殊在数组的键(索引)是数值类型

映射类型

映射类型:基于旧类型创建新类型(对象类型),减少重复、提升开发效率。

比如,类型PropKeys有x/y/z,另一个类型Type1中也有x/y/z,并且Type1中x/y/z的类型相同:

type PropKeys = 'x' | 'y' | 'z'type Type1 = { x: number; y: number; z: number }

这样书写没错,但x/y/z重复书写了两次。像这种情况,就可以使用映射类型来进行简化。

type PropKeys = 'x' | 'y' | 'z'type Type2 ={ [Key in PropKeys]: number }
  1. 映射类型是基于索引签名类型的,所以,该语法类似于索引签名类型,也使用了[ ]

  2. Key in PropKeys 表示 Key 可以是 PropKeys 联合类型中的任意一个,类似于 forin (let k in obj)。

  3. 使用映射类型创建的新对象类型 Type2 和类型 Type1 结构完全相同。

  4. 注意:映射类型只能在类型别名中使用,不能在接口中使用

映射类型除了根据联合类型创建新类型外,还可以根据对象类型来创建

type Props = { a: number; b: string; c: boolean }
type Type3 = { [key in keyof Props]: number }
  1. 首先执行`keyof Props获取对象类型Props中所有键的联合类型,即’a’|‘b’|‘c’
  2. 然后key in ...就表示key可以是Props中所有键的任意一个

泛型工具类Partial实现
在这里插入图片描述

索引查询类型

刚刚用到的T[P]语法,在TS中叫做索引查询(访问)类型
作用:用来查询属性的类型

type Props = { a: number; b: string; c: boolean }
type TypeA = Props['a']
  1. Props['a']表示查询类型Props中属性a对应的类型number,所以TypeA的类型为number
  2. [ ]中的属性必须存在于被查询类型中,否则报错

同时查询多个索引的类型

type Props = { a: number; b: string; c: boolean }
type TypeA = Props['a''b'] // 结果为: string | numbertype TypeB = Props[keyof Props] // 结果为: string | number | boolean

5.TypeScript类型声明文件

今天几乎所有的 JavaScript 应用都会引入许多第三方库来完成任务需求。
这些第三方库不管是否是用 TS 编写的,最终都要编译成 JS 代码,才能发布给开发者使用。
我们知道是 TS 提供了类型,才有了代码提示和类型保护等机制。
但在项目开发中使用第三方库时,你会发现它们几乎都有相应的 TS 类型,这些类型是怎么来的呢?类型声明文件类型声明文件:用来为已存在的 JS 库提供类型信息
这样在 TS 项目中使用这些库时,就像用 TS 一样,都会有代码提示、类型保护等机制了。

TS 的两种文件类型

TS 中有两种文件类型:1.ts文件 2.d.ts 文件。
.ts 文件:

  1. 既包含类型信息又可执行代码。

  2. 可以被编译为.js 文件,然后,执行代码。

  3. 用途:编写程序代码的地方。

.d.ts 文件:

  1. 只包含类型信息的类型声明文件。

  2. 不会生成 .js 文件,仅用于提供类型信息。

    1. 用途:为js 提供类型信息。

总结:.ts 是 implementation(代码实现文件).d.ts 是 declaration(类型声明文件) 。如果要为 JS 库提供类型信息,要使用.d.ts 文件。

类型声明文件的使用说明

使用已有的类型声明文件

使用已有的类型声明文件:1 内置类型声明文件 2 第三方库的类型声明文件。
内置类型声明文件TS 为 JS 运行时可用的所有标准化内置 API 都提供了声明文件。比如,在使用数组时,数组所有方法都会有相应的代码提示以及类型信息:
在这里插入图片描述

实际上这都是 TS 提供的内置类型声明文件。

可以通过 Ctrl+鼠标左键(Mac: option+鼠标左键)来查看内置类型声明文件内容。

比如,查看 forEach 方法的类型声明,在 VSCode中会自动跳转到lib.es5…d.ts 类型声明文件中。当然,像 window、document 等 BOM、DOMAPI也都有相应的类型声明(lib.dom.d.ts)。

第三方库的类型声明文件:目前,几乎所有常用的第三方库都有相应的类型声明文件。第三方库的类型声明文件有两种存在形式:1 库自带类型声明文件 2 由 DefinitelyTyped 提供。

  1. 库自带类型声明文件:比如,axios。

在这里插入图片描述
这种情况下,正常导入该库,TS 就会自动加载库自己的类型声明文件,以提供该库的类型声明。

  1. 由DefinitelyTyped提供。

DefinitelyTyped 是一个 github 仓库,用来提供高质量 TypeScript 类型声明。

可以通过npm/yarn来下载该仓库提供的TS类型声明包,这些包的名称格式为:@types/*。 比如,@types/react、@types/lodash 等。

说明:在实际项目开发时,如果你使用的第三方库没有自带的声明文件,VSCode 会给出明确的提示。

在这里插入图片描述

解释:当安装@types/*类型声明包后,TS 也会自动加载该类声明包,以提供该库的类型声明。

创建自己的类型声明文件

创建自己的类型声明文件:1 项目内共享类型 2 为已有 JS 文件提供类型声明。

项目内共享类型

如果多个.ts 文件中都用到同一个类型,此时可以创建.d.ts 文件提供该类型,实现类型共享。

操作步骤:

  1. 创建index.d.ts 类型声明文件。

  2. 创建需要共享的类型,并使用export导出(TS中的类型也可以使用import/export实现模块化功能)。

  3. 在需要使用共享类型的.ts 文件中,通过 import导入即可(.d.ts 后缀导入时,直接省略)。

为已有 JS 文件提供类型声明

  1. 在将 JS 项目迁移到 TS 项目时,为了让已有的 js 文件有类型声明。
  2. 成为库作者,创建库给其他人使用。

注意:类型声明文件的编写与模块化方式相关,不同的模块化方式有不同的写法。但由于历史原因,JS 模块化的发展经历过多种变化(AMD、CommonJS、UMD、ESModule 等),而 TS 支持各种模块化形式的类型声明。这就导致,类型声明文件相关内容又多又杂。

说明:在导入.js 文件时,TS 会自动加载与.js 同名的.d.ts 文件,以提供类型声明。

declare 关键字:用于类型声明,为其他地方(比如,。Js 文件)已存在的变量声明类型,而不是创建一个新的变量

  1. 对于 type、interface 等这些明确就是 TS 类型的(只能在 TS 中使用的),可以省略 declare 关键字。

  2. 对于 let、function 等具有双重含义(在 JS、TS 中都能用),应该使用 declare 关键字,明确指定此处用于类型声明。

如有不足,请多指教,
未完待续,持续更新!
大家一起进步!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_255492.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MG996R舵机介绍

舵机简介舵机是一种位置&#xff08;角度&#xff09;伺服的驱动器&#xff0c;适用于那些需要角度不断变化并可以保持的控制系统。在高档遥控玩具&#xff0c;如飞机、潜艇模型&#xff0c;遥控机器人中已经得到了普遍应用。舵机主要是由外壳、电路板、驱动马达、减速器与位置…

【c语言技能树】文件

Halo&#xff0c;这里是Ppeua。平时主要更新C语言&#xff0c;C&#xff0c;数据结构算法......感兴趣就关注我吧&#xff01;你定不会失望。 &#x1f308;个人主页&#xff1a;主页链接 &#x1f308;算法专栏&#xff1a;专栏链接 我会一直往里填充内容哒&#xff01; &…

NAS系列 硬件选择

转自我的博客文章https://blognas.hwb0307.com/nas/3224&#xff0c;内容更新仅在个人博客可见。欢迎关注&#xff01; 前言 经过《NAS系列 为什么你需要一台NAS》的简单介绍&#xff0c;如果你也决定像我一样组装一台自己的NAS&#xff0c;那么就千万不要错过本文喔&#xff…

负载均衡反向代理下的webshell上传+apache漏洞

目录一、负载均衡反向代理下的webshell上传1、nginx 负载均衡2、搭建环境3、负载均衡下的 WebShell连接的难点总结难点一、需要在每一台节点的相同位置都上传相同内容的 WebShell难点二、无法预测下次的请求交给哪台机器去执行。难点三、下载文件时&#xff0c;可能会出现飘逸&…

【3】深度学习之Pytorch——如何使用张量处理表格数据集(葡萄酒数据集)

张量是PyTorch中数据的基础。神经网络将张量输入并产生张量作为输出&#xff0c;实际上&#xff0c;神经网络内部和优化期间的所有操作都是张量之间的操作&#xff0c;而神经网络中的所有参数&#xff08;例如权重和偏差&#xff09;也都是张量。 怎样获取一条数据、一段视频或…

Springboot + RabbitMq 消息队列

前言 一、RabbitMq简介 1、RabbitMq场景应用&#xff0c;RabbitMq特点 场景应用 以订单系统为例&#xff0c;用户下单之后的业务逻辑可能包括&#xff1a;生成订单、扣减库存、使用优惠券、增加积分、通知商家用户下单、发短信通知等等。在业务发展初期这些逻辑可能放在一起…

openGL学习之GLFW和GLAD的下载和编译

背景:为什么使用GLFW和GLADOPenGL环境 目前主流的桌面平台是GLFW和GLAD之前使用的GLUT和Free GLUT已经基本淘汰了&#xff0c;所以记录一下如何下载GLFW和GLAD并且编译.GLFW下载:An OpenGL library | GLFW复制到你想存放的位置,我这里就存放到C盘Libaray文件夹下了,这里是我存放…

中国区注册使用ChatGPT指南(OpenAI‘s services are not available in your country)

ChatGPT又火了&#xff0c;各大平台热搜提到手软。暴增的访问量&#xff0c;即使强如ChatGPT&#xff0c;也表示顶不住了。Openai表示服务器已满负荷&#xff0c;ChatGPT暂无法提供服务由于目前ChatGPT未在中国开放&#xff0c;所以国内目前是无法注册使用ChatGPT。但我经过一番…

『 MySQL篇 』:MySQL表的聚合与联合查询

基础篇 MySQL系列专栏(持续更新中 …)1『 MySQL篇 』&#xff1a;库操作、数据类型2『 MySQL篇 』&#xff1a;MySQL表的CURD操作3『 MySQL篇 』&#xff1a;MySQL表的相关约束4『 MySQL篇 』&#xff1a;MySQL表的聚合与联合查询目录一. 聚合查询1.1 聚合函数1.2 GROUP BY子句…

Python将字典转换为csv

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。喜欢通过博客创作的方式对所学的知识进行总结与归纳,不仅形成深入且独到的理…

MySQL篇02-三大范式,多表查询

数据入库时,由于数据设计不合理&#xff0c;会存在数据重复、更新插入异常等情况, 故数据库中表的设计遵循的设计规范&#xff1a;三大范式1.第一范式(1NF)要求数据库的每一列都是不可分割的原子数据项&#xff0c;即原子性。强调的是列的原子性&#xff0c;即数据库中每一列的…

攀升MaxBook P2电脑U盘重装系统方法教学

攀升MaxBook P2电脑U盘重装系统方法教学。攀升MaxBook P2电脑是一款性价比非常高的笔记本。有用户购买了这款电脑后&#xff0c;想要将系统进行重装。今天和大家分享一个U盘重装系统的方法&#xff0c;学会这个方法后以后就可以自己轻松去重装电脑系统了。接下来一起看看具体的…

相机坐标系的正向投影和反向投影

1 、正向投影: 世界坐标系到像素坐标系 世界3D坐标系(x, y, z) 到图像像素坐标(u,v)的映射过程 &#xff08;1&#xff09;世界坐标系到相机坐标系的映射。 两个坐标系的转换比较简单&#xff0c;就是旋转矩阵 平移矩阵&#xff0c;旋转矩阵则是绕X&#xff0c; Y&#xff…

Thread 类及常见方法

Thread 类是 JVM 用来管理线程的一个类&#xff0c;换句话说&#xff0c;每个线程都有一个唯一的 Thread 对象与之关联。用我们上面的例子来看&#xff0c;每个执行流&#xff0c;也需要有一个对象来描述&#xff0c;类似下图所示&#xff0c;而 Thread 类的对象就是用来描述一…

分享111个JS焦点图代码,总有一款适合您

分享111个JS焦点图代码&#xff0c;总有一款适合您 111个JS焦点图代码下载链接&#xff1a;https://pan.baidu.com/s/1GxjW5m9DNOPEQd-Qf_gGSA?pwd4aci 提取码&#xff1a;4aci Python采集代码下载链接&#xff1a;https://wwgn.lanzoul.com/iKGwb0kye3wj jQuery宽屏左右…

没有人能比我快,用Python写一个自动填写答案的脚本

前言 不是标题党&#xff0c;真的就是没有人比我快&#xff0c;今天用Python写了个自动填写答案的脚本&#xff0c;快就算了&#xff0c;准确率还是百分之百 话不多说 咱先看代码 后看效果 不想看全文的 点击文末名片 领取源码 环境使用 Python 3.8Pycharm 模块使用 imp…

Request Method: OPTIONS

节选自https://blog.csdn.net/Amnesiac666/article/details/121105088版权归原作者所有&#xff0c;如有侵权请联系删除Request Method: OPTIONS一些接口在请求时&#xff0c;会自动发送一个的请求&#xff0c;我查了一遍代码&#xff0c;不是代码中写明的。 网上给出的解释涉及…

Pinecone:一款专为红队研究人员设计的WLAN网络安全审计框架

关于Pinecone Pinecone是一款专为红队研究人员设计的WLAN网络安全审计框架&#xff0c;该工具基于模块化开发&#xff0c;允许广大研究人员根据任务需求进行自定义功能扩展。Pinecone设计之初专用于树莓派&#xff0c;可以将树莓派打造为便携式无线网络安全审计工具&#xff0…

java面试题(十六)springBoot

1.1 说说你对Spring Boot的理解 参考答案 从本质上来说&#xff0c;Spring Boot就是Spring&#xff0c;它做了那些没有它你自己也会去做的Spring Bean配置。Spring Boot使用“习惯优于配置”的理念让你的项目快速地运行起来&#xff0c;使用Spring Boot很容易创建一个能独立运…

广告深度学习计算:向量召回索引的演进以及工程实现

问题定义召回操作通常作为搜索/推荐/广告的第一个阶段&#xff0c;主要目的是从巨大的候选集中选出相对合适的条目&#xff0c;交由后链路的排序等流程进行进一步的择优。因此&#xff0c;召回问题本质上就是一个大规模的最值的搜索问题&#xff1a;对于评分 和候选集 &#x…