文章目录

  • 前言
  • 一、TypeScript是什么
  • 二、TypeScript的好处
  • 三、TypeScript的优势
  • 四、TypeScript的开发环境
  • 五、编译并运行TS代码
  • 六、 简化运行TS的步骤
  • 七、TS常用的类型
  • 八、类型注解
  • 九、常用的类型
  • 十、数组类型
  • 十一、联合类型
  • 十二、pandas是什么?
  • 十三、函数类型 实质就是给函数参数和返回值加类型
    • 《1》单独指定参数 返回值的类型
    • 《2》同时指定参数 返回值的类型
  • 十四、void类型
  • 十五、函数类型
  • 十六、对象类型(有什么类型的属性和方法)
  • 十七、对象类型
  • 十八、接口
  • 十九、interface 和type的对比
  • 二十、接口继承
  • 二十一、元组
  • 二十二、类型推论
  • 二十三、类型断言
  • 二十四、字面量类型
  • 二十五、枚举
  • 二十六、字符串枚举
  • 二十七、枚举的特点及原理
  • 二十八、any类型
  • 二十九、typeof
  • 三十、TypeScript高级类型概述
    • 1.class类
    • 2.类型兼容性
    • 3.class类的构造函数
    • 4.class实例方法
    • 5.class继承
    • 6.class继承 接口
    • 7.类成员可见性
  • 三十一、类型兼容性
  • 三十二、对象之间的兼容性
  • 三十三、类型兼容性
    • 《1》接口兼容性
    • 《2》函数兼容性
  • 三十四、交叉类型和接口之间的对比
  • 三十五、泛型的使用
  • 三十六、简化泛型函数调用
  • 三十七、泛型约束
  • 三十八、多个泛型变量的情况
  • 三十九、泛型接口
  • 四十、泛型类(class也可以配合泛型来使用)
  • 四十一、泛型工具类型
    • 《1》Partial<Type>
    • 《2》Readonly<Type>
    • 《3》Pick<Type,Keys>
    • 《4》Record<Keys,Type>
  • 四十二、索引签名类型
  • 四十三、映射类型
  • 四十四、映射类型
  • 四十五、索引查询类型
  • 四十六、索引查询类型(同时查询多个)
  • 四十七、第三方库
  • 四十八、TS中的两种文件类型
  • 四十九、在React中使用TypeScript概述
  • 五十、React支持TS的项目目录结构
  • 五十一、TS配置文件tsconfig.json
  • 五十二、通过命令行方式使用编译配置
  • 五十三、React中的常用类型
  • 五十四、React函数组件的类型(1组件和属性类型)
  • 五十五、React函数组件的类型(2属性默认值)
  • 五十六、React函数组件的类型(3事件和事件对象)
  • 五十七、React类组件的类型(1组件类型)
  • 五十八、React类组件的类型(2组件属性)
  • 五十九、React类组件的类型(3状态和事件)
  • 六十、任务列表案例介绍

前言

哔哩哔哩课程链接: https://www.bilibili.com/video/BV14Z4y1u7pi?p=89&vd_source=92ee1c593b77f3dfb92819ea75999078


一、TypeScript是什么

TypeScript是JavaScript的超级 在JS的基础上增加了类型支持


二、TypeScript的好处

添加类型支持的好处:提高开发效率 减少找Bug的时间


三、TypeScript的优势

TS的优势:之一 类型推断机制 不需要在每个地方都显示标注类型


四、TypeScript的开发环境

安装环境 浏览器/node 只认识js代码 不认识ts代码 需要先将ts——>js 才能运行


五、编译并运行TS代码

1创建TS 2编译TS 3执行TS
执行指令 node .\test.js
注意:由TS编译生成的JS文件 代码中没有类型信息
ts:
let a : number = 100
console.log(a)
js:
var a = 100;
console.log(a);

六、 简化运行TS的步骤

问题:每次修改代码后 都要重复执行两个命令 才能运行TS 繁琐
简化方式:使用ts-node包 直接在node.js中执行ts代码
安装命令:npm i -g ts-node
使用方式:ts-node hello.ts
分析:ts-node命令在内部已经将TS->JS 再运行js代码


七、TS常用的类型

number、string、boolean、null、undefined、symbol


八、类型注解

为变量约定了类型 传值不符合规范会报错


九、常用的类型

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

十、数组类型


十一、联合类型

需求 数组中既有number类型 又有string类型


十二、pandas是什么?

类型别名(自定义类型):为任意类型起别名
使用场景:当同一类型(复杂)被多次使用时 可以通过类型别名 简化该类型的使用

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

解释:
《1》使用type关键字来创建类型别名
《2》类型别名 比如 此处的CustomArray 可以是任意合法的变量名称
《3》创建类型别名后 直接使用该类型别名作为变量的类型注解即可


十三、函数类型 实质就是给函数参数和返回值加类型

两种方式:

《1》单独指定参数 返回值的类型

function add(num1:number,num2:number):number{return num1+num2
}const add = (num1:number,num2:number):number=>{return num1+num2
}const add = () =>{} //箭头函数

《2》同时指定参数 返回值的类型

const cat: (num1: number, num2: number) => number = (num1, num2) => {return num1 - num2
}console.log(cat(2, 1))

十四、void类型

函数没有返回值 返回值类型为void


十五、函数类型

使用函数实现某个功能时 函数可以传参数也可以不传参数 在这种情况下
在给函数参数指定类型时 就可以用到可选参数了

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

可选参数:在可传可不传的参数名称后面添加?
注意:可选参数只能出现在参数列表的最后 就是说可选参数后面不能出现必选参数


十六、对象类型(有什么类型的属性和方法)

写法:

let person: { name: string, age: number, sayHi(): void } = {name: "张三",age: 10,sayHi: () => { }
}console.log(person)

注意: <1>如果一行代码只指定一个属性类型(通过换行来分割多个属性类型)可以去掉分号 <2>方法的类型也可以使用箭头函数的形式 sayHi:()=>void


十七、对象类型

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

function myAxios(config: { url: string, method?: string }) {console.log(config.url)
}
myAxios({url: 'https:www.baidu.com'
})

十八、接口

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

interface PersonI {name: stringage: numbersayHi: () => void
}let personi:PersonI ={name: "personi",age: 20,sayHi: function (): void {throw new Error("Function not implemented.")}
}

解释:
《1》使用interface关键字来声明接口
《2》接口名称可以是任意合法的变量名称
《3》声明接口后 直接使用接口名称作为变量的类型
《4》因为每一行只有一个属性类型 因此 属性类型后没有;号


十九、interface 和type的对比

相同点: 都可以给对象指定类型
不同点:类型别名 不仅可以为对象指定类型 实质上可以为任意类型指定别名


二十、接口继承

interface Point2D {x: numbery: number
}interface Point3D extends Point2D {z: number
}

二十一、元组

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

let position: number[] = [39.5427,116.2317]

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

let position : [number,number]=[39.5427,116.2317]

解释:
《1》元组类型可以确切地标记出有多少个元素 以及每个元素的类型
《2》该示例 元素中有两个元素 每个元素的类型都是number


二十二、类型推论

在TS中 某些没有明确指出类型的地方 TS的类型推论机制会帮助提供类型

let age = 13function addL(num1: number, num2: number) {return num1 + num2
}

二十三、类型断言

有时候你会比TS更加明确一个值的类型 此时 可以使用类型断言来指定更具体的类型

console.log($0)
console.dir($0)

解释:
《1》使用as关键字 实现类型断言
《2》关键字as后面的类型是一个更加具体的类型
《3》通过类型断言 aLink的类型变得更加具体 这样访问a标签特有的属性和方法
// const aLink = document.getElementById(‘link’) as HTMLAnchorElement
const aLink = document.getElementById(‘link’)
aLink.href


二十四、字面量类型

let str1 = "Hello TS"
// let str1: string
const str2 = "Hello TS"
// const str2: "Hello TS"

使用模式:字面量类型配合联合类型一起使用
使用场景:用来表示一组明确的可选值列表

比如 在贪吃蛇游戏中 游戏的方向的可选值只能是上,下,左,右

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

解释:参数direction的值只能是up/down/left/right
优势:相比于string类型 使用字面量类型更加精确 严谨


二十五、枚举

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

enum Direction { Up, Down, Left, Right }function changeDirection1(direction: Direction) {console.log(direction)
}

解释:
《1》使用enum 关键字定义枚举
《2》约定枚举名称 枚举中的值以大写字母开头
《3》枚举中的多个值之间通过(逗号)分割
《4》定义好枚举之后 直接使用枚举名称作为类型注解

注意:枚举成员是有值的 默认为:从0开始自增长的数值

枚举成员的值为数字的枚举 成为数字枚举
当然 也可以给枚举中的成员初始化值


二十六、字符串枚举

字符串枚举:枚举成员的值是字符串
字符串枚举没有自增长的行为 因此 字符串枚举的每个成员必须有初始值

enum Direction {Up = 'UP',Down = 'DOWN',Left = 'LEFT',Right = 'RIGHT'
}function changeDirection1(direction: Direction) {console.log(direction)
}changeDirection1(Direction.Up)
changeDirection1(Direction.Down)
changeDirection1(Direction.Left)
changeDirection1(Direction.Right)

二十七、枚举的特点及原理

枚举是TS为数不多的非JavaScript类型级扩展(不仅仅是类型)的特性之一。
因为:其他类型仅仅被当作类型 而,而枚举不仅用作类型 还提供值(枚举成员都是有值的)。
也就是说 其他的类型会在编译为JS代码时自动移除 但是 枚举类型会被编译为JS代码

enum Direction {Up = 'UP',Down = 'DOWN',Left = 'LEFT',Right = 'RIGHT'
}var Direction;
(function (Direction) {Direction["Up"] = "UP";Direction["Down"] = "DOWN";Direction["Left"] = "LEFT";Direction["Right"] = "RIGHT";
})(Direction || (Direction = {}));

二十八、any类型

不推荐使用any 这会让TypeScript变为 AnyScript 失去TS类型保护的优势

因为当值的类型为any时 可以对该值进行任意操作 并且不会有代码提示

解释:
《1》以上操作都不会有任何类型错误提示,即使可能存在错误
《2》其它 隐式具有any类型的情况
1.声明变量不提供类型也不提供默认值
2.函数参数不加类型


二十九、typeof

用来在JS中获取数据的类型

console.log(type "Hello World") //打印string

实际上 TS也提供了typeof操作符 可以在类型上下文中引用变量或属性的类型(类型查询)
使用场景:根据已有变量的值 获取该值的类型 来简化类型书写

let p = {x:1,y:2}
function formatPoint(point:{x:number;y:number}) {}
formatPoint(p)function formatPoint(point:typeof p) {}let p = { x: 1, y: 2 }// function formatPoint(point: { x: number; y: number }) {console.log("hello") }
function formatPoint(point: typeof p) { console.log("hello") }
formatPoint(p)

解释:
《1》使用typeof操作符来获取变量p的类型 结果与第一种(对象字面量形式的类型)相同
《2》typeof 出现在类型注解的位置(参数名称的冒号后面)所处的环境就在类型上下文(区别于JS代码)
《3》注意:typeof只能用来查询变量或属性的类型 无法查询其他形式的类型(比如 函数调用的类型)


三十、TypeScript高级类型概述

1.class类

TypeScript全面支持ES2015中引入的class关键字 并为其添加了类型注解和其他语法(比如 可见性修饰符等)
class基本使用 如下:

class Person {}
const per = new Person()

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

实例属性初始化

class Person{age: number
gender = '男'
// gender : string = '男'
}

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

2.类型兼容性

3.class类的构造函数

class Person{age : number
gender : string
constructor(age:number,gender:string){this.age = age
this.gender = gender
}
}

解释:
《1》成员初始化(比如 age:number)后 才可以通过this.age来访问实例成员。
《2》需要为构造函数指定类型注解 否则会被隐式推断为any 构造函数不需要返回值类型

4.class实例方法

class Point {x = 10y = 10scale(n: number): void {this.x *= nthis.y *= n}
}const point = new Point()
point.scale(10)
console.log(point.x, point.y)

解释:方法的类型注解(参数和返回值)与函数用法相同

5.class继承

类继承的两种方式
《1》extends(继承父类)
《2》implements(实现接口)
说明:JS中只有extends 而implements是TS提供的

class Animal {move() { console.log('Moving along!') }
}
class Dog extends Animal {bark() { console.log('汪!') }
}const dog = new Dog
dog.move()
dog.bark()

解释:
《1》通过extends关键字实现继承
《2》子类Dog继承父类Animal 则Dog的实例对象dog就同时具有了父类Animal和子类Dog的所有属性和方法

6.class继承 接口

interface Singable {sing(): void
}class Person implements Singable {sing(): void {console.log('我是你的小呀小苹果')}
}const per = new Person()
per.sing()

解释:
《1》通过implements关键字让class实现接口
《2》Person类实现接口Singable意味着 Person类中必须提供Singable接口中指定的所有方法和属性。

7.类成员可见性

类成员可见性:可以使用TS来控制class的方法或属性对于class外的代码是否是可见的
可见性修饰符包括:
《1》public 公有的 公开的
《2》protected 受保护的
《3》private 私有的

class Animal {public move() {console.log('Moving along!')}
}

解释:
《1》在类属性或方法前面添加public关键字 来修饰该属性或方法是共有的
《2》因为public是默认可见性 所以 可以直接省略

protected 表示受到保护的 仅对其声明所在的类和子类中(非实例对象)可见。

class Animal{protected move(){console.log('Moving along!')}
}
class Dog extends Animal{bark(){console.log('汪!')
this.move()
}
}

解释:
《1》在类属性或方法前面添加protected关键字 来修饰该属性或方法是受保护的。
《2》在子类的方法内部可以通过this来访问父类中受保护的成员 但是对实例不可见!

class类的可见性修饰符
private 表示私有的 只在当前类中可见 对实例对象以及子类也是不可见的

class Animal {private move(){ console.log('Moving along!')}
walk(){this.move()
}
}

解释:
《1》在类属性或方法前面添加private关键字 来修饰该属性或方法是私有的
《2》私有的属性或方法只在当前类中可见 对子类和实例对象也都是不可见的

readonly 只读修饰符

除了可见性修饰符之外 还有一个常见的修饰符就是:readonly(只读修饰符)
readonly:表示只读 用来防止在构造函数之外对属性进行赋值

class Person {readonly age: number = 18constructor(age: number) {this.age = age}
}const z = new Person(11)
z.age =1
// 无法分配到 "age" ,因为它是只读属性。ts(2540)

解释:
《1》使用readonly关键字修饰该属性是只读的 注意只能修饰属性不能修饰方法
《2》注意:属性age后面的类型注解(比如 此处的number)如果不加 则age的类型为18(字面量类型)
《3》接口或者{}表示的对象类型 也可以使用readonly


三十一、类型兼容性

两种类型系统:
《1》Structural Type System(结构化类型系统)
《2》 Nominal Type Syatem (标明类型系统)
TS 采用的是结构化类型系统 也叫做duck typing(鸭子类型)类型检查关注的是值所具有的形状

class Point {x:number;y:number}
class Point2D {x:number;y:number}const p : Point = new Point2D()

解释:
《1》point和Point2D是两个名称不同的类
《2》变量p的类型被显示标注为Point类型 但是 它的值却是Point2D的实例 并且没有类型错误
《3》因为TS是结构化类型系统 只检查Point和Point2D的结构是否相同(相同 都具有x和y两个属性 属性类型也相同)
《4》但是 如果在Nominal Type System中 (比如C# Java等)它们是不同的类 类型无法兼容


三十二、对象之间的兼容性

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

class Point {x:number | undefined ; y:number | undefined}
class Point3D {x:number | undefined ; y:number | undefined ; z:number | undefined}

解释:
《1》Point3D的成员至少与Point相同 则Point兼容Point3D
《2》所以 成员多的Point3D可以赋值给成员少的Point


三十三、类型兼容性

除了class之外 TS中的其他类型也存在相互兼容的情况
包括:

《1》接口兼容性

接口之间的兼容性 类似于class 并且 class和interface之间也可以兼容
多的给少的

interface Point {x: numbery: number
}interface Point2D {x: numbery: number
}interface Point3D {x: numbery: number
}let p1: Point
let p2: Point2D
let p3: Point3D//正确:
// p1 = p2
// p2 = p1
// p1 = p3// 错误演示:
// p3 = p1class Point3D {x:number ; y:number ; z:number}
let p3:Point2D = new Point3D()

《2》函数兼容性

函数之间的兼容性比较复杂 需要考虑
1》参数个数 参数多的兼容参数少的 或者说 参数少的可以赋值给多的

   type F1 = (a:number)     => voidtype F2 = (a:number,b:number) => voidlet f1 : F1let f2 : F2// 正确f2 = f1// 错误示范 不能将类型“F2”分配给类型“F1”。f1 = f2

解释:
1. 参数少的可以赋值给参数多的 所以f1可以赋值给f2
2.数组forEach方法的第一个参数是回调函数 该示例中类型为:
(value:string,index:number,array:string[])=>void
3.在JS中省略用不到的函数参数实际上是很常见的 这样的使用方式 促成了TS中函数类型之间的兼容性
4.并且因为回调函数是有类型的 所以 TS会自动推导出参数item index array的类型
const arr = [‘a’,‘b’,‘c’]
arr.forEach(()=>{})
arr.forEach((item)=>{})

2》参数类型

type F1 = (a:number)=>string
type F2 = (a:number)=>string
let f1: F1
let f2: F2 = f1

解释:函数类型F2兼容函数类型F1 因为F1和F2的第一个参数类型相同

参数类型复杂的情况

interface Point2D {x:number ; y:number}
interface Point3D {x:number ; y:number ; z:number}
type F2 = (p: Point2D)=> void
type F3 = (p: Point3D)=> void
let f2:F2
let f3:F3 = f2
f2=f3

解释:
1.此处与前面讲到的接口兼容性冲突
2.技巧:将对象拆开 把每个属性看作一个个参数 则参数少的可以赋值给参数多的
3》返回值类型
只关注返回值类型本身即可

type F5 = () => string
type F6 = () = > string
let f5 : F5
let f6 : F6 = f5//
type F7 = ()=>{name:string}
type F8 = () =>{name:string ; age:number}
let f7 : F7
let f8 : F8
f7 = f8

解释:
1》如果返回值类型是原始类型 此时两个类型要相同 比如 左侧类型是F5和F6
2》如果返回值类型是对象类型 此时成员多的可以赋值给成员少的 比如 右侧类型F7和F8

交叉类型
类似于之前的接口继承
功能类似于接口继承(extends)用于组合多个类型为一个类型(常用于对象类型)
比如:

interface Person { name: string }
interface Cotact { phone: string }type PersonDetail = Person & Cotactlet obj: PersonDetail = {name: 'Jack',phone: '12'
}console.log(obj)
//{ name: 'Jack', phone: '12' }

解释:
使用交叉类型后 新的类型PersonDetail就同时具备了Person和Contact的所有属性类型
相当于:
type PersonDetail = {name:string; phone:string}


三十四、交叉类型和接口之间的对比

相同点:都可以实现对象类型的组合
不同点:两种方式实现类型组合时 对于同名属性之间 处理类型冲突的方式不同

interface A {fn: (value: number) => string
}
interface B extends A {fn: (value: string) => string
}type C = A & B

说明 以上代码 接口继承会报错(类型不兼容)
交叉类型没有错误 可以简单理解为
fn : (value : number } string) => string


三十五、泛型的使用

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

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

比如 id(10)调用以上函数就会直接返回10本身 但是该函数只接收数值类型 无法用于其他类型
但是也不能够加any 便会失去ts的保护机制

function id<Type>(value:Type):Type {return value}

创建泛型函数:

《1》语法 在函数名称的后面添加<>(尖括号)尖括号中添加类型变量 比如此处的Type
《2》类型变量Type 是一种特殊类型的变量 它处理类型而不是值
《3》该类型变量相当于一个类型容器 能够捕获用户提供的类型(具体是什么类型
由用户调用该函数时指定)
《4》因为Type是类型 因此可以将其作为函数参数和返回值的类型 表示参数和返回值具有相同的类型
《5》类型变量Type 可以是任意合法的变量名称

function id<Type>(value: Type): Type { return value }const id_1 = id<number>(1)
const id_2 = id<string>('123')console.log(id_1, id_2)
//1 123

解释:
《1》语法:当函数名称的后面添加<>(尖括号)尖括号中指定具体的类型 比如 此处的number
《2》当传入类型number后 这个类型就会被函数声明时指定的类型变量Type捕获到
《3》此时 Type的类型就是number 所以 函数id参数和返回值的类型也都是number
同样的 如果传入类型string 函数id参数和返回值的类型都是string
这样 通过泛型就做到了让id函数与多种不同的类型一起工作 实现了复用的同时保证了类型安全


三十六、简化泛型函数调用

解释:
《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(value: Type): Type {
console.log(value.length)
return value
}

1》指定更加具体的类型

function id<Type>(value: Type[]): Type[] {console.log(value.length)return value
}
比如 将类型修改为Type[] (Type类型的数组) 因为只要是数组就一定存在length属性
因此便可以访问了
//
function id<Type>(value: Type[]): Type[] {console.log(value.length)return value
}console.log(id([1, 2, 3, 4, 5]))

2》添加约束

interface ILength { length: number }function id<Type extends ILength>(value: Type): Type {console.log(value.length)return value
}console.log(id([1, 2, 3, 4, 5]))

解释:
《1》创建描述约束的接口ILength 该接口要求提供length属性
《2》通过extends关键字使用该接口 为泛型(类型变量)添加约束
《3》该约束表示:传入的类型必须具有length属性
注意:传入的实参(比如 数组)只要有length属性即可 这也符合前面讲到的接口的类型兼容属性。


三十八、多个泛型变量的情况

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

function getProp<Type, Key extends keyof Type>(obj: Type, Key: Key) {return obj[Key]
//返回key中所对应的值
}let person1 = { name: 'jack', age: 18 }getProp(person1, 'name')

解释:
《1》添加了第二个类型变量Key 两个类型变量之间使用(,)分隔
《2》keyof关键字接收一个对象类型 生成其键名称 (可能是字符串或数字)的联合类型
《3》本示例中keyof Type实际上获取的是person对象所有键的联合类型 也就是:‘name’|‘age’
《4》类型便可i昂Key受Type约束 可以理解为:Key只能是Type所有键中的任意一个 或者说只能访问对象中存在的属性


三十九、泛型接口

接口也可以配合泛型来使用 以增加其灵活性 增强其复用性

interface IdFunc<Type>{id : (value:Type)=>Type
ids:() = > Type[]
}let obj : IdFunc<number> = {id(value) {return value},
id(){return [1,3,5]}
}

解释:
<1>在接口名称的后面添加<类型变量>那么 这个接口就变成了泛型接口
<2>接口的类型变量 对接口中所有其他成员可见 也就是接口中所有成员都可以使用类型变量
<3>使用泛型接口时 需要显示指定具体的类型
<4>此时 id方法的参数和返回值类型都是number ids方法的返回值类型是number[]

数组是泛型接口
实际上 JS中的数组在TS中就是一个泛型接口

const strs = ['a', 'b', 'c']
strs.forEach(item => {})
//(method) Array<string>.forEach(callbackfn: (value: string, index: number, array: string[]) => void, thisArg?: any): void
const nums = [1, 3, 5]
nums.forEach(item=>{})
//(method) Array<number>.forEach(callbackfn: (value: number, index: number, array: number[]) => void, thisArg?: any): void

解释:
《1》当我们在使用数组时 TS会根据数组的不同类型 来自动将类型变量设置为相应的类型
《2》技巧 可以通过Ctrl + 鼠标左键 来查看具体的类型信息


四十、泛型类(class也可以配合泛型来使用)

比如:React的class组件的基类Component就是泛型类 不同的组件有不同的props和state

解释:
React.Component泛型类两个类型变量 分别指定props和state类型
interface IState { count: number }
interface IProps { maxLength: number }

class InputCpunt extends React.Component<IProps, IState>{
state: IState = {
count: 0
}

render() {return <div>{ this.props.maxLength }</div>
}

}

创建泛型类:

class GenericNumber<NumType>{defaultValue: NumType | undefinedadd: ((x: NumType, y: NumType) => NumType) | undefined}

解释:
《1》类似于泛型接口 在class名称后面添加<类型变量>这个类就变成了泛型类
《2》此处的add方法 采用的就是箭头函数形式的类型书写方式
const myNum = new GenericNumber()
console.log(myNum.defaultValue = 10)

省略参数的写法

class GenericNumber<NumType>{defaultValue: NumType | undefinedadd: ((x: NumType, y: NumType) => NumType) | undefinedconstructor(value: NumType) {this.defaultValue = value}
}const myNum = new GenericNumber(100)
console.log(myNum.defaultValue)

类似于泛型接口 在创建class实例时 在类名后面通过<类型>来指定明确的类型


四十一、泛型工具类型

TS内置了一些常用的工具类型 来简化TS中的一些常见操作
说明:它们都是基于泛型实现的(泛型适用于多种类型 更加通用)并且是内置的 可以直接在代码中使用。
主要学习以下几个

《1》Partial

泛型工具类型 Partial用来构造(创建)一个类型 将Type的所有属性设置为可选。

interface Props {id: stringchildren: number[]
}type PartialProps = Partial<Props>//Partial
type PartialProps = {id?: string | undefined;children?: number[] | undefined;
}

调用:

let p1: Props = {id: "1",children: [1, 2, 3, 4]
}let p2: PartialProps = {id: '123'
}

《2》Readonly

用来构造一个类型 将Type的所有属性都设置为readonly(只读)

interface Props {id: stringchildren: number[]
}type PartialProps = Readonly<Props>let p1: PartialProps = {id: "1",children: [1, 2, 3, 4]
}
//无法分配到 "id" ,因为它是只读属性。
p1.id = '3'

解释:当我们重新给id属性赋值时 就会报错 无法分配到“id”因为它是只读属性

《3》Pick<Type,Keys>

《4》Record<Keys,Type>

type RecordObj = Record<'a' | 'b' | 'c', string[]>// type RecordObj = {//     a: string[]
//     b: string[]
//     c: string[]
// }let obj: RecordObj = {a: ['1'],b: ['2'],c: ['3']
}console.log(obj)
//{ a: [ '1' ], b: [ '2' ], c: [ '3' ] }

解释:
《1》Record工具类型有两个类型变量
1.表示对象有哪些属性
2.表示对象属性的类型
《2》构建的新对象类型RecordObj表示:这个对象有三个属性分别为a/b/c 属性值的类型都是string[]

四十二、索引签名类型

绝大多数情况下 我们都可以在使用对象前就确定对象的结构 并为对象添加准确的类型
使用场景:当无法确定对象中有哪些属性(或者说对象中可以出现任意多个属性)此时 就用到索引签名类型了

interface AnyObject {[key: string]: number
}let obj: AnyObject = {a: 1,abc: 124,abde: 12345
}
//{ a: 1, abc: 124, abde: 12345 }
console.log(obj)

解释:
《1》使用[key:string]来约束该接口中允许出现的属性名称 表示只要是string类型的属性名称 都可以出现在对象中
《2》这样 对象obj中就可以出现任意多个属性(比如 a b等等)
《3》key 只是一个占位符 可以换成任意合法的变量名称
《4》隐藏的前置知识 JS中对象 ({})的键是string类型的
在js中数组是一类特殊的对象 特殊在数组的键(索引)是数值类型
并且 数组也可以出现任意多个元素 所以在数组对应的泛型接口中 也用到了索引签名类型
解释:
《1》MyArray接口 模拟原生的数组接口 并使用[n:number]来作为索引签名类型。
《2》该索引签名类型表示:只要是number类型的键(索引)都可以出现在数组中 或者说数组中可以有任意多个元素
《3》同时也符合数组索引是number类型这一前提

interface MyArray<T> {[n: number]: T
}let arrs: MyArray<number> = [1, 3, 5]//[ 1, 3, 5 ]
console.log(arrs)

四十三、映射类型

映射类型:基本旧类型创建新类型 (对象类型),减少重复 提升开发效率
比如:类型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 PropKeys = 'x' | 'y' | 'z'
type Type1 = { x: number; y: number; z: number }
type Type2 = { [Key in PropKeys]: number }let obj1: Type1 = {x: 0,y: 0,z: 0
}let obj2: Type2 = {x: 0,y: 0,z: 0
}console.log(obj1)
console.log(obj2)
//
{ x: 0, y: 0, z: 0 }
{ x: 0, y: 0, z: 0 }

四十四、映射类型

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

type Props = {a:number;b:string;c:boolean}
type Type3 = {[Key in keyof Props]:number}
let obj: Type3 = {a: 0,b: 0,c: 0
}console.log(obj)
//{ a: 0, b: 0, c: 0 }

使用[]来访问对象的属性 P是对象中的键
获取T对象中键为P的值

解释:
《1》keyof T 即keyof Props表示获取Props的所有键 也就是:‘a’|‘b’|‘c’
《2》在[]后面添加?(问号)表示将这些属性变为可选的 以此来实现Partial的功能
《3》冒号后面的T[P]表示获取T中每个键对应的类型 比如 如果是’a’则类型是number 如果是’b’ 则类型是string
《4》最终 新类型PartialProps和旧类型Props结构完全相同 只是让所有类型都变为可选了


四十五、索引查询类型

刚刚用到的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 }
// string | number
// type TypeA = Props['a' | 'b']
// string | number | boolean
type TypeA = Props[keyof Props]

解释:
《1》使用字符串字面量的联合类型 获取属性a和b对应的类型 结果为string | number
《2》使用keyof操作符获取Props中所有键对应的类型 结果为string | number | boolean


四十七、第三方库

类型声明文件:用来为已存在的JS库提供类型信息
《1》TS的两种文件类型
《2》类型声明文件的使用说明


四十八、TS中的两种文件类型

1.ts文件 2 .d.ts文件

.ts文件:
《1》既包含类型信息又包含可执行代码
《2》可以被编译为.js文件 然后 执行代码
《3》用途:编写程序代码的地方

.d.ts文件:
《1》只包含类型信息的类型声明文件
《2》不会生成.js代码 仅用于提供类型信息
《3》用途:为JS提供类型信息
总结:
.ts是implementation(代码实现文件)
.d.ts是declaration(类型声明文件)
如果要为JS提供类型信息 要使用.d.ts文件

在使用TS开发项目时 类型声明文件的使用包含以下两种方式

《1》使用已有的类型声明文件
《2》创建自己的类型声明文件

学习顺序:先会用(别人的)再会写(自己的)

《1》使用已有的类型声明文件
*1.内置类型声明文件
TS为JS运行时可用的所有标准化内置API都提供了声明文件。
比如 在使用数组时 数组所有方法都会有相应的代码提示以及类型信息

(method) Array<number>.forEach(callbackfn: (value: number, index: number, array: number[])
=> void, thisArg?: any): void

实际上这都是TS提供的内置类型声明文件
可以通过Ctrl + 鼠标左键来查看内置类型声明文件内容
比如 查看forEach方法的类型声明 在VSCode中会自动跳转到lib.es5.d.ts类型声明文件中
当然 像window document等BOM DOM API也都有相应的类型声明(lib.dom.d.ts)
2.第三方库的类型声明文件
《1》库自带类型声明文件
比如 axios
解释:在这种情况下 正常导入该库 TS就会自动加载自己的类型声明文件 以提供该库的类型声明
《2》由DefinitelyTyped提供
这是一个github仓库 用来提供高质量TypeScript类型声明
可以通过npm/yarn来下载该仓库提供的TS类型声明包 这些包的名称格式为:@types/

比如 @types/react @types/lodash
说明:在实际开发时 如果你使用的第三方库没有自带的声明文件 VSCode会给出明确的提示


解释:
《1》当安装@types/*类型声明后 TS也会自动加载该类声明包 以提供该库的类型声明
《2》补充:TS官方提供了一个页面 可以来查询@types/*库

第一步
在该链接中找到命令:
https://www.typescriptlang.org/dt/search?search=lodashnpm i lodash
npm i @types/lodash --save-dev第一个是下载库的
第二个是下载声明文件的在终端仅执行第一个指令后 在index.ts文件中引入
import _ from 'lodash'
报错:
无法找到模块“lodash”的声明文件。“D:/codeFiles/VsCodeProjects/vscode-typescript/node_modules/lodash/lodash.js”隐式拥有 "any" 类型。尝试使用 `npm i --save-dev @types/lodash` (如果存在),或者添加一个包含 `declare module 'lodash';` 的新声明(.d.ts)文件ts(7016)其它范例:
npm i react
npm i @types/react --save-dev

《2》创建自己的类型声明文件

  1. 项目内共享类型

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

  3. 项目内共享类型

如果多个.ts文件中都用到同一个类型 此时可以创建.d.ts文件提供该类型 实现类型共享
操作步骤:
《1》创建index.d.ts 类型声明文件
《2》创建需要共享的类型 并使用export导出(TS中的类型也可以使用import/export实现模块化功能)
《3》在需要使用共享类型的.ts文件中 通过import导入即可(.d.ts后缀导入时 直接省略)

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

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

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

演示:
基于最新的ESModule (import/export)来为已有.js文件 创建类型声明文件。
开发环境准备:使用webpack搭建 通过ts-loader处理.ts文件

说明:TS项目中也可以使用.js文件
说明:在导入.js文件时 TS会自动加载与.js同名的.d.ts文件 以提供类型声明
declare关键字:用于类型声明 为其它地方(比如.js文件)已存在的变量声明类型 而不是创建一个新的变量
《1》对于type interface 等这些明确就是TS类型的(只能在TS中使用的)可以省略declare关键字
《2》对于let function 等具有双重含义(在JS TS中都能用)应该使用declare关键字 明确指出此处使用declare关键字 明确指定此处用于类型声明


四十九、在React中使用TypeScript概述

在前端项目开发中使用TS 还需要掌握React Vue Angular等这些库或框架中提供的API的类型 以及在TS中是如何使用的

接下来 以React为例 来学习如何在React项目中使用TS 包括以下内容:

《1》使用CRA创建支持TS的项目

React脚手架工具create-react-app(简称:CRA)默认支持TypeScript
创建支持TS的项目命令:npx create-react-app 项目名称 --template typescript
当看到以下提示时 表示支持TS的项目创建成功
We suggest that you begin by typing:
cd react-ts-basic
npm start


五十、React支持TS的项目目录结构

相对于非TS项目 目录结构主要由以下三个变化
1.项目根目录中增加了tsconfig.json配置文件 指定TS的编译选项 (比如 编译时 是否移除注释)
2.React组件的文件扩展名变为:*.tsx
3.src目录中增加了react-app-env.d.ts:React项目默认的类型声明文件。react-app-env.d.ts:React项目默认的类型声明文件
三斜线指令 : 指定依赖的其它类型声明文件 types表示依赖的类型声明文件包的名称
/// <reference types="react-scripts" />
解释:
告诉TS帮我加载react-scripts这个包提供的类型声明。
react-scripts的类型声明文件包含了两部分类型
《1》react react-dom node的类型
《2》图片 样式等模块的类型 以允许在代码中导入图片 SVG等文件。TS会自动加载该.d.ts文件 以提供类型声明(通过修改tsconfig.json中的include配置来验证)

五十一、TS配置文件tsconfig.json

指定项目文件和项目编译所需的配置项
注意:TS的配置项非常多(100+)以CRA项目中的配置为例来学习 其它的配置项用到时查文档即可
《1》tsconfig.json文件所在目录为项目根目录(与package.json同级)
《2》tsconfig.json 可以自动生成 命令 tsc-init


五十二、通过命令行方式使用编译配置

使用演示:tsc hello.ts --target es6
注意:
1. tsc 后带有输入文件时(比如 tsc hello.ts)将忽略tsconfig.json
2. tsc 后不带输入文件时 (比如 tsc)才会启用tsconfig.json
推荐使用 : tsconfig.json 配置文件

五十三、React中的常用类型

前提说明:现在 基于class组件来讲解React+TS的使用 (最新的React Hooks 在后面讲解)
在不使用TS时 可以使用prop-types库 为React组件提供类型检查
说明:TS项目中 推荐使用TypeScript实现组件类型校验(代替PropTypes)
不管是React还是Vue 只要是支持TS的库 都提供了很多类型 来满足该库对类型的需求
注意:
1.React项目是通过 @types/react @types/react-dom 类型声明包 来提供类型的
2.这些包 CRA已帮我们安装好(react-app-env.d.ts)直接用即可


五十四、React函数组件的类型(1组件和属性类型)

React是组件化开发模式 React开发主要任务就是写组件
两种组件:
《1》函数组件
1.组件的类型
2.组件的属性(props)
3.组件属性的默认值(defaultProps)
4.事件绑定和事件对象type Props = {name:string;age?:number}
const Hello:FC <Props> = ({name,age})=>(
<div>你好,我叫:{name},我 {age} 岁了</div>
)
<Hello name="jack"/>
实际上 还可以直接简化为 (完全按照函数在TS中的写法)
const Hello = ({name,age}: Props) = >(
<div>你好,我叫:{name},我 {age} 岁了</div>
)

五十五、React函数组件的类型(2属性默认值)

函数组件属性的默认值(defaultProps)
const Hello:FC<Props> = ({name,age}) =>(
<div>你好,我叫:{name},我{age}岁了</div>
)
Hello.defaultProps = {age: 18
}
实际上 还可以直接简化为(完全按照函数在TS中的写法)
const Hello = ({name,age=18}:Props) =>(
<div>你好,我叫:{name},我{age}岁了</div>
)

五十六、React函数组件的类型(3事件和事件对象)

事件绑定和事件对象
<button onClick={onClick}>点赞</button>
const onClick = () =>{}
const onClick1=(e:React.MouseEvent<HTMLButtonElement>) =>{}
再比如 文本框
<input onChange={onChange}/>
const onChange = (e:React.ChangeEvent<HTMLInputElement>) =>{}
技巧:在JSX中写事件处理程序(e=>{})然后 把鼠标放在e上 利用TS的类型推论来查看事件对象类型
<input onChange={e=>{}}>

五十七、React类组件的类型(1组件类型)

《2》class组件 主要包含以下内容:
1.组件的类型 属性 事件
type State = {count:number}
type Props ={message?:string}class C1 extends React.Component {}  //无props state
class C2 extends React.Component<Props> {} //有props 无state
class C3 extends React.Component <{},State>{}//无props 有state
class C4 extends React.Component <Props,State>{}//有props state2.组件状态(state)

五十八、React类组件的类型(2组件属性)

class组件的属性和属性默认值
type Props = {name:string;age?:number}
class Hello extends React.Component<Props>{static defaultProps:Partial<Props> = {age:18
}render(){const {name,age} = this.propsreturn <div>你好,我叫:{name},我{age}岁了</div>}
}const {name,age=18} = this.props//解构
const {name,age} = this.props

五十九、React类组件的类型(3状态和事件)

class组件状态(state)和事件
type State = {count:number}
class Counter extends React.Component<{},State>{state:State = {count : 0
}
onIncrement=() =>{this.setState({count:this.state.count+1
})
}
}<button onClick={this.onIncrement}>+1</button>

六十、任务列表案例介绍

TS+React实现todos案例
功能演示:
《1》展示任务列表
《2》添加任务父组件:App
子组件:TodoAdd TodoList展示任务列表:
思路:使用状态提升(为父组件提供状态 通过props传递给子组件)来实现父->子通讯步骤:
《1》为父组件App 提供状态(任务列表数据)和类型
《2》为子组件TodoList指定能够接收到的props类型
《3》将任务列表数据传递给TodoList组件//后面没必要看了

TypeScript快速上手相关推荐

  1. 什么是 TypeScript ? 快速上手 TypeScript

    什么是 TypeScript ? TypeScript是一种由微软开发的开源编程语言,它是JavaScript语言的一个超集,支持JavaScript中的所有语法和特性,并在此基础上添加了一些新的特性 ...

  2. Typescript快速上手(js转ts必备)

    接口interface 1.定义一个接口 LabelledValue ,在传参数的时候使用labelledObj:LabelledValue interface LabelledValue {labe ...

  3. 快速上手 TypeScript

    快速上手 TypeScript ypeScript 简称 TS ,既是一门新语言,也是 JS 的一个超集,它是在 JavaScript 的基础上增加了一套类型系统,它支持所有的 JS 语句,为工程化开 ...

  4. 【TypeScript】(一)快速上手TypeScript类型语法

    文章目录 1.概述 2.TS中的类型 2.1.类型推断 2.2.类型定义 2.3.复杂类型 2.3.1.联合 2.3.2.泛型 2.4.type关键字 3. 总结 1.概述 TypeScript(TS ...

  5. WijmoJS 2019V1正式发布:全新的在线 Demo 系统,助您快速上手,开发无忧

    2019独角兽企业重金招聘Python工程师标准>>> 下载WijmoJS 2019 v1 WijmoJS是为企业应用程序开发而推出的一系列包含HTML5和JavaScript的开发 ...

  6. Vue-cli 3.X 构建工具零基础快速上手

    文章目录 一.环境准备 1. 安装node 2. 配置镜像 二.安装Vue CLI 2.1. 查看当前vuecli版本 2.2. 安装最新版本 2.3. 安装指定版本 三.创建web项目 3.1. 指 ...

  7. 【HTML】重点知识内容~快速上手

    推荐前端学习路线如下: HTML.CSS.JavaScript.noodJS.组件库.JQuery.前端框架(Vue.React).微信小程序和uniapp.TypeScript.webpack 和 ...

  8. 「自动化测试」新一代 Web 前端自动化测试框架 —— playwright 快速上手,轻松带入项目

    playwright上手 内网如何安装项目依赖 注意:想运行 playwright需要下载相关浏览器的二进制文件 由于默认情况下,Playwright 会从 Microsoft CDN 下载浏览器二进 ...

  9. Angular 初学者快速上手教程

    课程介绍 本课程是一个系列基础教程,目标是带领读者上手实战,课程以新版本 Angular 的 3 个核心概念作为主线:组件.路由.模块,加上业务开发过程中必须用到的特性:工具.指令.表单.RxJS.i ...

  10. 【快速上手mac必备】常用优质mac软件推荐(音视频、办公、软件开发、辅助工具、系统管理、云存储)

    本文章的主要内容是我作为一名大四学生.准程序员.up主这三种身份来给大家推荐一下 mac 上好用的软件以及工具.本人也是从去年9月份开始从windows阵营转移到了mac阵营,刚开始使用的时候,也曾主 ...

最新文章

  1. mark一下总是记混的重定向与转发的区别
  2. 高并发,高性能的一点调研
  3. webpack --- 发布环境的配置 代码压缩 代码分类
  4. c车模电磁循迹代码_电磁炉检修快速入门
  5. linux 线程id 进程id,在Linux上显示正在运行的进程的线程ID
  6. C#语言中循环分类总结
  7. 《『若水新闻』客户端开发教程》——14.代码编写(6)
  8. PHP file_get_contents(‘php://input‘) 和POST的区别
  9. java实现对称加密—基本实现
  10. Android手机sock5代理免root
  11. 腾讯地图拾取坐标html,GitHub - cloydlau/coord-picker: 高德/腾讯地图坐标拾取器 / A coordinates picker for amap/tmap...
  12. matlab拟合函数导出,excel里曲线拟合的公式怎么导出?()
  13. PLSQLDeveloper14连接Oracle11g
  14. pytorch实现bnn
  15. mongodb分片集群数据库安全认证
  16. 专升本英语——应试题型突破——翻译——名言警句【学习笔记】
  17. Android使用微信H5支付
  18. H3C SecPath F100 系列防火墙基本配置
  19. jmeter 运行接口报javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection的解决方法
  20. 一个屌丝程序猿的人生(九十四)

热门文章

  1. 采用numpy快速将两个矩阵或数组合并成一个数组和行列转置
  2. 【现已失效】【转载】QQ空间一键点赞方法
  3. mybatis批量删除 java_Mybatis批量删除数据操作方法
  4. 《中华颂》朗诵比赛准备
  5. Java IO基础知识
  6. android恢复微信好友,安卓微信好友误删怎么办?这样有效恢复!
  7. 基于物联网的智慧农业监测系统(前端界面有web端和微信小程序端)
  8. 百度地图、高德地图的数据下载
  9. ps抠图技巧,抠头发
  10. python span()函数_Python正则表达式六种函数实例讲解