Typescript 基础知识梳理

Typescript 包含了 Javascript 的所有内容,是 Javascript 的超集。在 JS 基础上,增加了静态类型检查、接口、泛型等特性,更适合大型项目开发。

一、类型声明

使用 :  来对变量或函数形参和返回值,进行类型声明

let a: string
function fun(x: number, y: number):number { ... }
let b : 'hello' //字面量类型,让变量 b 的值只能为'hello',开发中不常用

二、类型推断

TS 会根据我们的代码,进行类型推导,例如下面代码中的变量 d,只能存储数字类型

let d = -99
d = false // ts 会对此行代码报错,不能把布尔类型分配给数值类型

 三、常见类型与方法

TS 的数据类型包含 JS 的所有数据类型(字符串、数值、布尔、undefined、null、symbol、bigint、Object....),还扩展了一些数据类型(any、unknown、never、void、元组、枚举......)

TS 类型中 string 与 String 的区别:

string 类型只包括字符串的原始值类型,String 类型则还包括了使用 String 包装对象定义的字符串,number 与 boolean 同理。

1、any

任意类型,一旦使用则表示放弃了对该变量的类型检查。

any 类型的变量,可以赋值给其他任意类型的变量。

2、unknown

未知类型,可以理解为一个类型安全的 any(不能直接赋值给其他类型),适用于不确定数据类型的具体类型。

unknown 会强制开发者在使用之前进行类型检查,从而提供更强的类型安全性。

let a: unknown
a = 'hello world'

let x: string
// 类型判断
if (typeof a === 'string') {
  x = a
}
// 加断言
x = a as string
x = <string>a
(a as string).toUpperCase()

 3、never

never 的含义是任何值都不是,一般是 TS 主动推断出来的,也可限制函数的返回值(限制函数不能有返回值,null、undefined 也不行)

function throwError(str: string):never {
  throw new Error('程序执行异常:' + str)
}

4、void

通常用于函数的返回值,含义:函数不返回任何值,调用者不应依赖其返回值进行任何操作

void 与 undefined 的区别:

使用 undefined 限制函数的返回值,调用者依然可以对返回值进行操作,而使用 void 则会进行限制(调用者不能使用返回值进行任何操作)

5、object

object 与 Object 类型限制范围太过宽泛,所以开发中不常使用(object 限制非原始值类型,Object 则除了 null 与 undefined 的所有值都在允许的范围)

在开发中我们可以使用字面量类型的方式来代替 object 与 Object

let obj: {name: string, age: number}
obj = {name: 'tom', age: 18}

对于对象属性存在缺少或有多余的情况,我们可以这样操作:

let person: {
  name: string, 
  age?: number, // 属性可选
  [key: string]: any // 索引签名
}

person = { name: 'tom', age: 18, gender: 'male', city: 'beijing'}

声明函数类型(也可用接口或自定义类型的方式):

// count 变量限制为形参为 x、y 返回值为 number 类型的函数
let count: (x: number, y: number) => number

count = function(a, b) { 
  // 因为上面已经进行了限制,所以这里可以省略相关代码
  return a + b
}

声明数组类型:

let arr1: string[] // 限制数组元素的类型为字符串
let arr2: Array<number> // 泛型,限制数组元素的类型为数值型

6、元组(tuple)

一种特殊的数组类型,可以存储固定数量,并且每个元素的类型是已知的且可以不同,也可以使用? 设置可选

let arr1: [string, number]
let arr2: [string, boolean?] // 设置可选
let arr3: [boolean, ...string[]] // 可以有任意多个 string 类型
arr1 = ['123', 456]
arr2 = ['hello']
arr3 = [false, 'hello', 'world']

7、枚举(enum)

enum 可以定义一组命名常量,增强代码的可读性,也让代码更好维护。

// 1、数字枚举,其成员的值会自动递增,且具备反向映射的特点,默认从 0 开始
enum Direction {
  Up, Down
}
function walk(str: Direction) { // 限制 str 只能为 Direction 中的值
  if (str === Direction.Up) {
    console.log('向上走')
  } else if (str === Direction.Down) {
    console.log(向下走)
  }
}

walk(Direction.Right)

// 2、字符串枚举,丢失了反向映射
enum Direction {
  Up = 'up', Down = 'down'
}

// 3、常量枚举,使用 const 关键字定义,在编译时会被内联,避免生成冗余代码
const enum Direction {
  Up, Down
}

8、type(自定义类型)

// 1、联合类型,它表示一个值可以是几个不同类型之一
type Status = number | string
type Gender = 'male' | 'female'


// 2、交叉类型
type Area = {
  width: number,
  height: number
}
type Address = {
  room: string
}
type House = Area & Address // 必须兼具 Area 与 Address 的属性
const house: House = {
  width: 100,
  height: 100,
  room: '3 号楼 101'
}

9、一个特殊情况

使用类型声明限制函数返回值为 void 时,TS 并不会严格要求函数返回空,这样是为了保证类似 ES6 箭头函数的简写形式的相关代码成立。

type LogFunc = () => void // 已经限制返回值为 void
const f1: LogFunc = function() {
  return '此时却可以 return 任何类型的值'
}
const f2: LogFunc = () => 666

10、属性修饰符

属性的简写形式:

// 简写前
class Person {
  public name: string
  public age: number
  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }
}
// 简写后,只保留构造器
class Person {
  constructor(public name: string, public age: number) {}
}

11、抽象类

抽象类是一种无法被实例化的类,专门用来定义类的结构和行为,类中可以写抽象方法,也可以写具体实现。抽象类主要用来为其派生类提供一个基础结构,要求其派生类必须实现其中的抽象方法。抽象类不能实例化,其意义是可以被继承。

abstract class Package {
  constructor(public weight: number) {}
  // 抽象方法,无函数体
  abstract calculate():number 
 // 具体方法
  printPackage() {
    console.log(`包裹的重量为:${this.weight}kg,运费为:${this.calculate} 元`)
  }
}

class StandardPackage extends Package {
  constructor(
    weight: number,
    public unitPrice: number
  ){ super(weight) }
  calculate():number {
    return this.weight * this.unitPrice
  }
}

12、interface(接口)

interface 是一种定义结构的方式,主要作用是为类、对象、函数等规定一种契约,这样可以确保代码的一致性和类型安全,interface 只能定义格式,不能包含任何实现。

① interface 定义类、对象、函数的结构

// 定义类的结构
interface PersonInterface {
  name: string,
  age?: number, // 可选属性
  readonly sex: string, // 只读属性
  speak(n: number): void
}
class Person implements PersonInterface {
  constructor(public name: string, public age: number) { }
  speak(n: number): void {
    for (let index = 0; index < n; index++) {
      console.log(this.name + ',' + this.age)
    }
  }
}
// 定义对象的结构
const person: PersonInterface = {
  name: '张三',
  sex: '男',
  speak: function (n: number): void {
    console.log(n)
  }
}
// 定义函数的结构
interface CountInterface {
  (a: number, b: number): number
}
const countFn: CountInterface = function (x, y): number {
  return x + y
}

② 接口的继承

interface PersonInterface {
  name: string
  age: number
}
interface studentInterface extends PersonInterface {
  grade: string
}
const student: studentInterface = {
  name: 'John',
  age: 18,
  grade: '12th'
}

③ 接口的可合并性

interface PersonInterface {
  name: string
  age: number
}
interface PersonInterface {
  grade: string
}
const person: PersonInterface = {
  name: 'John',
  age: 30,
  grade: 'A'
}

13、一些相似概念的区别

① interface 与 type 的区别

相同点:interface 与 type 都可以定义对象的结构,两者在许多场景都是可以互换的

// 使用 interface 定义 person 对象
interface PersonInterface {
  name: string
  age: number
  speak(): void
}
// 使用 type 定义 person 对象
type PersonType = {
  name: string
  age: number
  speak(): void
}

 不同点:

interface 更专注与定义类和对象的结构,支持继承、合并;

type 可以定义类型别名、联合类型、交叉类型,但不支持继承与自动合并

② interface 与抽象类的区别

相同点:都可以定义类的格式

不同点:

接口只能描述结构,不能有任何具体实现的代码,一个类可以实现多个接口

抽象类既可以包含抽象方法,也可以包含具体方法,一个类只能继承一个抽象类

interface FlyInterface {
  fly: () => void
}
interface WalkInterface {
  walk: () => void
}
class Animal implements FlyInterface, WalkInterface {...}

四、泛型

泛型允许我们在定义函数、类、接口时,使用类型参数来表示未指定的类型,这些参数在具体使用时,才被指定具体的类型。泛型能让同一段代码适用于多种类型,同时仍然保证类型的安全性。

// 泛型的示例
function logData<T>(data: T) {
  console.log(data)
}
logData<string>('hello')
logData<number>(123)
// 泛型可以有多个
function logData<T, U>(data: T, msg: U): T|U {
  console.log(data)
  console.log(msg)
  return Date.now() % 2 ? data : msg
}
logData<string, string>('hello', 'world')
logData<string, number>('hello', 2)
// 泛型接口
interface PersonInterface<T> {
  name: string,
  age: number,
  introduce: T
}
const person: PersonInterface<string> = {
  name: 'zhangsan',
  age: 18,
  introduce: 'hello'
}
// 泛型类
class Person<T> {
  constructor(public name: T) {}
}
type JobInfo = {
  title: string,
  salary: number
}
let p = new Person<JobInfo>({
  title: '前端开发工程师',
  salary: 10000
})

版权声明:
作者:灰糖
链接:https://guwenhan.com/typescripthczssl/
来源:灰糖笔记
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
< <上一篇
下一篇>>
文章目录
关闭
目 录