经常使用ts的你,知道这些内容?

149 阅读7分钟

ts的优势

  • 编译时静态类型检测:函数或方法传参或变量赋值不匹配时,会出现编译错误提示,规避了开发期间的大量低级错误,省时,省力。
  • 自动提示更清晰明确。因为在编译阶段就确定了变量类型,所以语法提示更清晰。
  • 引入了泛型和一系列的TS特有的类型。
  • 强大的d.ts声明文件,声明文件像一个书的目录一样,清晰直观展示了依赖库文件的接口,type类型,类,函数,变量等声明。
  • 轻松编译成JS文件,即使TS文件有错误,绝大多数情况也能编译出JS文件。
  • 灵活性高:尽管TS是一门强类型检查语言,但也提供了any类型和as any断言,这提供了TS的灵活度

类型推导和类型注解的区别

类型推导在定义时未约束类型,类型注解在定义时就被约束了类型。

Object、{}和object区别

  • Object是根类型(number, string, boolean, undefined, null, symbol, bigint),但是null, undefined不能赋值给Object类型。
  • {}是Object的简写。
  • object只能赋值对象类型(数组,对象,函数等等)。null, undeined也不能进行赋值给object类型。

联合类型(|), 交叉类型(&)

  • 当联合类型被赋值后,他的类型就已经是确定的独立类型了,而不是联合类型了。

image.png

  • 类型想要交叉就必须有交集才可以。

never如何使用和呈现

never 表示永远不会发生值的类型。

如果我们指定一个函数参数为string和number的联合类型,并在其中做出string和number的判断,那么else部分获取该参数就是never的类型。

never类型的一个重要特点是,可以赋值给任意其他类型。

function f(): never {
  throw new Error("Error");
}

let v1: number = f(); // 不报错
let v2: string = f(); // 不报错
let v3: boolean = f(); // 不报错

为啥使用枚举

用于存放一组固定的常量序列。

  • 如果枚举的值是数字类型,那么它具有双重映射,既可以使用key获取value,也可以使用value获取key。
  • 如果枚举的值是字符串类型,那么它只具有单层映射,即只能通过key获取value。

没有枚举之前我们只能规定特定类型,降低了代码的可读性和可维护性。

any和unknown的区别

  • any可以是任何类型的父类型也可以是任何类型的子类型。
let a: any = "1"
// any可以赋值给任何类型变量 (就好比后端返回的类型为any,然后赋值给前端中的一个特定类型的变量)
let b:number = a
  • unknown可以是任何类型的父类型,但是不能是任何类型的子类型。
let a1: unknown = 1
let b: string = a1 // error
  • 不能使用unknown类型的变量获取任何属性和方法,但是可以使用any类型的变量获取属性和方法。

unknown使用场景:一般用于函数参数类型约束,并且该参数用于内部函数参数传递,不获取属性和方法。

function bar(params:any) {
  console.log(params)
}

function foo(params: unknown) {
  return bar(params)
}

接口

定义对象类型。

优点

  • 可以继承
  • 类可以实现接口。相同类型的类可以实现相同接口,统一定义一个接口让若干相同类型的类实现。(为多个同类别的类统一提供方法和属性声明)
  • 可索引签名。我们在定义可索引签名时,值类型一定要兼容具体的接口属性值类型。
interface List {
  // 这里的key为string并不是表示对象键名必须是string类型
  [key: string]: any
}
const list: List = {
  1: "1",
  false: "1",
  [Symbol()]: "1",
  key: "1"
}
  • 同名接口会进行合并。
  • 获取接口属性类型。
interface List {
  [symbolId]: 1,
  name: string,
  age: number
}
// 这个就好比枚举属性值可以赋值给枚举类型一样
type t1 = List["name"] // string
type t2 = List["name" | "age"] // string | number
type t3 = List[typeof symbolId] // 1
  • 获取接口属性字面量类型。
type t4 = keyof List // typeof symbolId | "name" | "age" | "fn"

type AllKeys<T> = T extends any ? T : never
type t5 = AllKeys<keyof List>

ts中的undefined, null

在js中null 表示的是:“定义了但是为空”。所以,在实际编程时,我们一般不会把变量赋值为 undefined,这样可以保证所有值为 undefined 的变量,都是从未赋值的自然状态。

在ts中如果我们将undefined,null赋值给指定类型的变量他将存在编译错误(在开启了strictNullChecks属性时)这就强制不让我们给已经决定类型的变量赋值undefined,null。如果想要赋值就必须使用联合类型将undefined或者null设置进去。

let s:string = null; // error
let s1:string | null = null

undefined只能赋值给undefined, any, unknown类型,null只能赋值给 null, any, unknown类型。

动态属性获取对象属性编译错误

  • 变量属性充当动态属性获取对象属性出现编译错误。
let name = "name"
const obj = {
  name: "zh",
  age: 18
}

const n = obj[name] // error, 因为name变量可能会发生变化,使用const定义即可。
  • 指定对象类型为object/Object时,再通过动态属性获取对象属性时出现编译错误。因为object类型不能进行解析赋值后的对象属性(即不能准确解析具有的属性)。
const name = "name"
const obj: object = {
  name: "zh",
  age: 18
}

const n = obj[name] // error

interface 与 type区别

  • 定义范围不同
    • interface只能定义对象类型或者接口当名字的函数类型。
    • type可以定义任何类型,包括基本类型,联合类型,交叉类型,元组。
  • 接口可以继承其他接口和type,类可以实现接口,但是type没有继承功能。
  • 接口可以合并声明,相同名称的接口可以合并,但是type不能。

约束数组元素不改变

使用断言。

const a = [1,2,3] as const
a[0] = 1 // error

可变元组

我们知道元组是一个固定数量和确定类型的数组。

我们可以通过...any[]形式定义一个可变元组。使用于前几个元素类型固定,而且是不固定长度的数组变量。

const users: [string, number, boolean, ...any[]] = ["1", 1, true, 1, null, undefined]

为可变元组元素命名。主要是可以更直观的表达每个元素的意义。

const [name, age, sex, ...rest]: [_name: string, _age: number, _sex: number, ...rest: any[]] = ["zh", 20, 1, "669638556@qq.com"]

ts中getter和setter的意义

主要是对属性的赋值做约束。一般不在构造函数中进行约束,一般构造函数直接进行属性赋值,不做逻辑处理。

tsconfig.json

请看这里

往期年度总结

往期文章

专栏文章

结语

本篇文章到此就结束了,欢迎在评论区交流。

🔥如果此文对你有帮助的话,欢迎💗关注、👍点赞、⭐收藏✍️评论,   支持一下博主~