TS内容学习总结

  • 前期背景
    • js和java区别
    • 为什么学习TS
    • TypeSscript类型
  • 基础类型
  • 数组类型
  • 类型别名
  • 函数类型
  • void类型
  • 可选参数
  • 对象
  • 接口interface
      • interface VS type
      • 接口继承
      • type 如何和 interface 一样实现继承的效果?
  • 元组Tuple
  • 字面量
  • 枚举类型
      • 数字枚举
      • 字符串枚举
      • 枚举实现原理
  • any类型
  • 类型断言
  • 泛型
      • 泛型约束
      • 多个类型变量
      • 泛型接口

前期背景

js和java区别

  • JS:解释型,弱类型,动态语言
  • Java:编译型,强类型,静态语言

解释:

  • 解释型:我们写的代码,无需进行编译,直接运行,也需要一个翻译器,一遍翻译一边执行
  • 编译型:人类写的是英语,机器不认识,需要一个编译器,将人们写的语言转换成机器识别的语言,这个过程叫编译
  • 弱类型:声明变量时无需指定类型
  • 强类型:声明变量时必须指定类型
  • 动态语言:在代码执行的过程中可以动态添加对象的属性
  • 静态语言:不允许在执行过程中随意添加属性

结论:js的特点是灵活、高效,很短的代码就能实现复杂功能,缺点是没有代码提示,容易出错且编辑工具不会给任何提示,而Java则相反。

TS可以简单理解为将JavaScript转变为Java一类语言的过程。

为什么学习TS

  • 从编译语言的动静来区分,TS属于静态类型的变成语言,JS属于动态类型的编程语言
    • 静态类型:编译期做类型检查
    • 动态类型:执行期做类型检查
  • 对于JS来说,需要等到代码真正去执行的时候才能发现错误(晚), 对于TS来说,在代码编译的时候(代码执行前)就可以发现错误(早);

并且,配合VSCode等开发工具,TS可以提前到在编写代码的同时就发现代码中的错误,减少找Bug,改Bug时间,另外还支持代码提示

Vue3的源码使用TS重写,Angular默认支持TS、React与TS完美配合,TypeScript已经成为大中型前端项目的首选变成语言。
注意:Vue2对TS的支持不好~

TypeSscript类型

类型注解总结:

  • 将来不能将其他类型的值赋予这个变量
  • 代码有提示,在变量后面.可以直接看到当前类型所支持的所有属性和方法

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

  • JS已有类型
    • 原始类型,简单类型(number、string、boolean、null、undefined)
    • 复杂数据类型(数组、对象、函数等)
  • TS新增类型
    • 联合类型
    • 自定义类型(类型别名)
    • 接口
    • 元组
    • 字面量类型
    • 枚举
    • void
    • 。。。

基础类型

// 字符串类型
let a:string = '123';

数组类型

let arr:number[] = [123]

//这样会报错定义了数字类型出现字符串是不允许的
let arr:number[] = [1,2,3,'1']

//数字类型的数组
var arr: number[] = [1, 2, 3];
//字符串类型的数组
var arr2: string[] = ["1", "2"];


// 数组泛型,规则 Array<类型>
let arr:Array<number> = [1, 2, 3, 4, 5];

// 多维数组
let data:number[][] = [[1,2], [3,4]];

//任意类型的数组
var arr3: any[] = [1, "2", true];

// 希望数组里面可以存数字或字符串
// 联合类型 |
let arr4:(number | string)[] = [1, 2, 4, '2323'];
// 注意:| 的优先级较低,需要用()包裹提升优先级
// 一旦使用联合类型,说明 arr 中存储的既可能是number 也可能是 string,所以会丢失一部分提示信息

// 定时器?

类型别名

目标:能够使用类型别名给类型起别名。
使用场景:当同一类型(复杂)被多次使用时,可以通过type定义类型别名(推荐使用大写字母开头),简化该类型的使用。

// 希望 N 个数组里面可以存数字或字符串
// 方法1:里面上面的联合类型
// 方法2:类型别名
type ArrType = (number | string)[]

let arr1: ArrType = ['1', 2, 4, '2323'];
let arr2: ArrType = [1, '2', 4, '2323'];
let arr3: ArrType = [1, 2, '4', '2323'];


// 灵活度很高,可以随意搭配组合使用
type ItemType = number | string
let arr4: ItemType[] = [1, 2, '3', '123'];
let arr5: ItemType = '23'

// 总结:将一组类型存储到【变量】里,用 type 来声明这个特殊的【变量】

// 玩花活
type s = string
type n = number

let str2: s = '123'
let num2: n = 123

函数类型

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

  • 单独指定参数、返回值的类型
  • 同时指定参数、返回值的类型
// ts 要求我们必须给参数定义类型,而返回值它会自动推断
// 函数声明
function add(a: number, b: number) {
	return a + b;
}

// 箭头函数,ts中的箭头函数必须是小括号
const sub = (a: number, b: number): number => {
	return a + b;
}


// 函数的类型别名
type FnType = (a: number, b: number) => number

// 函数的类型别名通常是给箭头函数/函数表达式使用,不会给函数声明使用

const fn: FnType = function(a, b) {
  return a + b
}

void类型

如果函数没有返回值,那么,在TS的类型中,函数返回值类型为void

const sayHello = (content: string): void => {
  console.log(content)
}

// 但,如果指定返回值类型为 undefined,此时,函数体中必须显示的 return undefined 才可以
const addN = (): undefined => {
  return undefined
}

可选参数

  • 使用函数实现某个功能时,参数可以传也可以不传。这种情况下,在给函数参数指定类型时,就用到可选参数。在可选可不传的参数名称后面添加?
  • 注意:可选参数只能出现在参数列表的最后,也就是说可选参数后面不能再出现必选参数。
const printP = (name: string, age?: number): void => {
  console.log(name, age)
}

printP('哆啦A梦', 18)
printP('波多野结衣')

对象

JS中的对象是由属性和方法构成的,而TS对象的类型就是在描述对象的结构(有什么类型的属性和方法)。
调用对象时可以直接提示有哪些属性和方法

// ts 就像咋写注释,以前写的注释是给程序员看的,ts 写的类型是给编辑器看的,程序员也可以看
let obj: {
  name: string,
  age: number,
  sayHi: (content: string) => void
} = {
  name: '哆啦A梦',
  age: 18,
  sayHi(content) {
    console.log(content)
  }
}

// 类型别名用法

// 对象类型
type Person = {
  name: string,
  age: number,
  sayHi: (content: string) => void 
}

let obj1: Person = {
  name: '哆啦A梦',
  age: 18,
  sayHi(content) {
    console.log(content)
  }
}

方法类型的两种定义形式

// 方法的类型也可以使用箭头函数形式
type Person = {
  greet: (name: string) => void
  // greet(name: string) => void
}
let person: Person = {
  greet(name) {
    console.log(name)
  }
}

接口interface

当一个对象类型多多次使用时,一般会使用接口(interface)来描述对象的类型,达到复用的目的。
作用:给对象约束属性和方法

// 基础用法:
interface IPerson {
  name: string
  age: number
  sayHi: () => void
}

const p1: IPerson = {
  name: '苍老师',
  age: 18,
  sayHi() {
    console.log('i like')
  }
}
  • 使用interface关键字声明接口
  • 接口名称可以是任何合法的变量名称,推荐以I开头
  • 声明接口后,直接使用接口名称作为变量的类型
  • 因为每一行只有一个属性类型,因此,属性类型后没有;(分号)

interface VS type

总结:
interface 和 type 的区别,接口interface 只能约束对象,而类型别名 type 不仅可以为对象指定类型,实际上可以为任何类型指定别名。
推荐:能使用type就使用type,更灵活,更简单

接口继承

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

// 比如,这两个接口都有x、y两个属性,重复写两次,可以,但是很繁琐
interface Point2D {
  x: number
  y: number
}

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

// 更好的方式
interface Point2D {
  x: number
  y: number
}

// 继承Point2D
interface Point3D extends Point2D {
  z: number
}

type 如何和 interface 一样实现继承的效果?

type Person = {
  usename: string
  age: number
  sayHi: () => void
}

//  & 与连接符:既要满足前面的也要满足后面的
//  | 或连接符:满足其中一个即可
type Student = {
  score: number
  sleep: () => void
} & Person

接口继承:可以实现让一个接口使用另一个接口的类型约束,实现接口的复用。

元组Tuple

限定数组的固定类型和数据长度,元组类型时另一种类型的数组,他确切地知道包含多少个元素,以及特定索引对应的类型。

// 地图经纬度
let arr6: [number, number] = [13.334, 36.2323]

字面量

字面量类型就是把字面量当做类型来用。eg:

let s1 = 'hello TS';
const s2 = 'hello TS';

通过TS类型推论机制,可以得到:s1的类型时string,s2的类型为 ‘hello TS’;
解释:s2是一个常量,它的值不能变化只能是 ‘hello TS’,所以,它的类型为 ‘hello TS’。此次 ‘hello TS’,就是一个字面量类型,也就是说某个特定的字符串也可以作为TS中的类型

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

比如:在贪吃蛇游戏中,游戏的方向的可选值只能是上、下、左、右中的任意一个

枚举类型

枚举的功能类似于字面量类型+联合类型组合的功能,也可以表示一组明确的可选值;
枚举:定义一组命名常量。它描述一个值,该值可以是这些命名常量中的一个
如果不设置值,默认从 0 开始

// 创建枚举
enum Direction {
  Up,
  Dowm,
  Left,
  Right
}

// 使用枚举类型
function changeDirection(direction: Direction) {
  console.log(direction)
}
  • 使用enum关键字定义枚举
  • 约定枚举名称以大写字母开头
  • 枚举中多个值之间通过,(逗号)分割
  • 定义好枚举后,直接使用枚举名称作为类型注释

数字枚举

我们把枚举成员的值为数字的枚举,称为数字枚举。注意:枚举成员是有值的,默认为:从0开始自增的数值

// 给枚举中的成员初始化值
enum Direction {
  Up = 10,
  Dowm,
  Left,
  Right
}
//  Dowm => 11, Left => 12, Right => 13

字符串枚举

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

enum Direction {
  Up = 'Up',
  Dowm = 'Dowm',
  Left = 'Left',
  Right = 'Right'
}

枚举实现原理

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

// 会被编译为以下代码:
(function (Direction) {
    Direction[Direction["Up"] = 0] = "Up";
    Direction[Direction["Dowm"] = 1] = "Dowm";
    Direction[Direction["Left"] = 2] = "Left";
    Direction[Direction["Right"] = 3] = "Right";
})(Direction || (Direction = {}));

说明:枚举与前面安静到的字面量类型+联合类型组合的功能类似,都用来表示一组明确的可选值列表。
一般情况下,推荐字面量类型 + 联合类型组合的方式,因为相比枚举,这种方式更加直观、简洁、高效。

any类型

any类型:原则上不推荐使用,只有在迫不得已的时候才可以用一下,否则会变成 AnyScript,失去 TS 类型保护机制

let obj2: any = {x: 0}

const n: number = obj2

尽可能的避免使用any类型,除非临时使用any来避免书写很长、很复杂的类型,其他隐式具有any类型的情况

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

注意:因为不推荐使用any,所以,这两种情况下都应该提供类型

类型断言

类型断言:强行指定获取到的结果类型
有时候你会比TS更加明确一个值的类型,此时,可以使用类型断言来指定更具体的类型,eg:
const aLink = document.getElementById('link')
注意:该方法返回值的类型是HTMLElement,该类型只包含所有标签公共的属性和方法,不包含a标签特有的href等属性,因此,这个类型太宽泛,无法操作href等a标签特有的属性和方法
解决办法:这种情况下就需要使用类型断言指定更加具体的类型。

const aLink = document.getElementById('link') as HTMLAnchorElement
// aLink.href, 敲代码段的时候直接有提示
  • 使用as关键字实现类型断言
  • 关键字as后面的类型时一个更加具体的类型 (HTMLAnchorElement)

另一种写法,使用<> 语法,不常用,知道即可
const alink2 = document.getElementById('link')

总结:当函数获取到的结果类型较为宽泛时,我们有知道具体类型,就可以使用断言强行指定类型。

泛型

泛型是可以保证类型安全前提下,让函数等与多种类型一起工作,从而实现复用,常用于:函数、接口、class中。
泛型在保证类型安全(不丢失类型信息的同时,可以让函数等与多种不同的类型一起工作,灵活可复用。)

// 定义一个getId,传入一个值,返回这个值,可以传入任意类型
// any 可以解决问题,但也会带来问题:返回值也是any没有提示了
function getId(val: number | string | boolean) {
	return val
}

解决方案:

// 期望:调用getId函数时来指定传入参数的类型
//  在声明泛型
// (val: T) 使用泛型
// 调用函数时传入泛型指定的具体类型
function getId<T>(val: T) {
  return val
}

console.log(getId<number>(123))
console.log(getId<string>('123'))

// 简化泛型函数调用,  也可以使用,调用时不用加<>
console.log(getId(123))

上面的T和下面的Type是一样的,知识变量名称不同罢了

泛型约束

// 如下代码:当传输string,正确,当输入number时,报错,所以需要对val进行约束,即:泛型约束
function getId<T>(val: T) {
  console.log(val.length)
  return val
}

添加约束(常见方法)

// 定义接口
interface ILength {
  length: number
}

// 使用,添加约束,给泛型找爸爸
function getId<T extends ILength>(val: T) {
  console.log(val.length) // 输入val代码提示length属性
  return val
}
  • 通过extends 关键字使用该接口,为泛型添加约束
  • 该约束表示:传入的类型必须具有length属性

多个类型变量

泛型的类型变量可以有多个,并且类型变量之间还可以约束(比如,第二个类型变量受第一个类型变量约束)

// 需求,定义一个函数,传入一个对象,在传入一个字符串属性名,返回属性值
function getProp(obj: object, key: string) {
	return obj[key] // 这种方式会报错,不知道是否这个key
}
function getProp<O, K extends keyof O>(obj: O, key: K) {
	return obj[key]
}

let person = {name: 'jack', age: 18}
getProp(person, 'name')
  • 添加第二个类型变量key,两个类型变量之间使用 ,逗号分隔
  • keyof 关键字接收一个对象类型,生成其键名称(可能是字符串或数字)的联合类型
  • 本示例中 keyof O 实际上获取的是person对象所有键的联合类型,也就是:‘name’ | ‘age’
  • 类型变量key受O约束,可以理解为:key只能是O所有键中的任意一个,或者说只能访问对象中存在的属性

泛型接口

interface Student {
	id: number
	name: string
	hobby: string[]
}
let s1: Student = {
	id: 123,
	name: '波多小姐',
	hobby:['瑜伽', '运动', '歌唱']
}

// 转化
interface Student<T> {
	id: number
	name: T
	hobby: T[]
}

let s1: Student<string> = {
	id: 123,
	name: '波多小姐',
	hobby:['瑜伽', '运动', '歌唱']
}

参考:
链接

你可能感兴趣的:(TypeScript,学习,typescript,前端)