• 作者:老汪软件技巧
  • 发表时间:2024-09-03 07:01
  • 浏览量:

前言

在学习 typescript 中,我们会用到很多的类型,但又其实一些 type 相关的操作类型,有时让我们眼花缭乱,我们简单介绍一些 typescript 中的一些类型

并且主要讲解 typeof、keyof、in、extends、infer、as、函数部分操作等内容

大多数学习参考都是点赞、收藏一些常用的知识点,看了之后会忘,毕竟超忆症的人还是少,对于大多数人来说,仍然是“好记性不然烂笔头”,点赞、收藏、书写等都是我们记录的一个过程,需要时从大脑->文章查询,后面慢慢常用的自己就记住了

比如我之前经常会翻阅 typescript中常见的高级类型,里面相对比较常用的,例如: Pick、Omit、Partial、Required、Record、Exclude、Extract、ReturnType等,混合的只要自己理解了很容易搭配

ts中文文档、(以前看过的)

下面主要讲解 typeof、keyof、in、extends、infer、as、函数部分操作等内容

typeof、keyof、in、extends、infer、as等介绍typeof

typeof 可以判断、取出一个对象的类型

判断类型,这也是比较常用的,有时进行归一化处理时会用到,甚至有些常见场景也会用到

//获取字符类型
const str: string = ""
//判断类型(除了这个,判断实例类型 instanceof 也是比较常见的)
if (typeof str === 'string') {
    //这是true
}

取出类型

//获取对象类型
const obj1 = {
    a: '',
    n: '',
}
type Obj1Type = typeof obj1
//取出来的类型就是这个
type Str1Type = {  
    a: string;  
    n: string;  
}
//获取字符类型
const str: string = "a"
//取出类型 string,如果前面未声明,取出的类型就可能是一个字符串"a",声明字符串就是字符串类型
type StrType = typeof str // string类型
//需要注意的是字符集、数字等对象也可以是指定的类型
type STRRR = 'a'  //类型就是 'a'
type STRRR = 'a' | 'b'  //类型是联合类型 'a' | 'b'

keyof

keyof操作符可以用来一个对象中的所有 key 值,并且取出的值是一个联合类型 A | B,联合类型使用 |关键字

interface Person {
    name: string;
    age: number;
}
type P1 = keyof Person; // "name" | "age"
//如果是数组,则取出了数组对象的key
type P2 = keyof Person[]; // "length" | "toString" | "pop" | "push" | "concat" | "join" 

in

可以用来判断一个对象中是否有某一个字段

interface Person {
    name: string;
    age: number;
}
function judgeExist(p: Person) {
    if ("name" in p) {
        // 表示name 是否在 p 中
        //当然实际 也可以理解为 p 中是否存在 name,p["name"] 作为判断条件,没有 in 方便罢了
    }
}

可以用来枚举遍历一个对象,生成新类型

extends

这个是比较常见的继承功能,而 interface、type等也是包含其多态的一些用法,这就不多介绍了

先简单介绍下我们 extends 的常用

//基类
class Person {
    name: string
    ...
}
//extends 继承
class Man extends Person {
    sex: string = 'man'
    ...
}
//接口
interface Speaking {
    speak: () => void;
}
//继承 + 接口实现,简单提一下不多说
class Woman extends Person implements Speaking {
    sex: string = 'woman'
    speak() {}
}

interface、extends除了上面那种class中的常规用法,我们发现 interface、type、extends在类型体操中有着自己的作为,只不过仅仅用于声明类型

type Person {
    name: string
}
//extends 除了继承interface,也可以继承 type 的类型
interface Woman extends Person {
    sex: boolean
}
type Sex {
    sex: boolean
}
//此时 type 这个类型是不是和 extends 表示相同的类型了
//这里的 Man、Woman 实际上表示的类型是一样的
type Man = Person & Sex
//interface、type形成的类型是一致的,可以共同使用,只不过操作方式略有不同
//即:一个声明需要 extends,一个需要 & 罢了
type Woman2 = Woman & Sex

上面的 & 表示并且的意思,和 |不一样, &会将对象整合成一个新的对象类型,而 |有或的意思,表示此类型或者另外一个类型,这个联合类型|仅仅就是联合起来,&更像是变异形成新个体

此外 type 中也可以使用 extends,但不是上面那种使用方式

type Person {
    name: string
}
//这泛型在函数中使用也是比较常见的
function pushextends Person>(item: T) {}
//当然class类中也一样,掌握了基础,也能更加灵活使用,再配上其他的一些类型操作,会更加得心应手
class Stackextends Person> {
    items: T[] = [];
}

infer

infer 有推断的意思,能让我们从一个复杂类型中推断出其中包含的某一个类型,使用其占位,然后通过占位的类型,推断出我们需要的类型,一般其伴随着 extends 函数出现,毕竟平时用不到

介绍中等职业学校作文_介绍中等教育作文_

我们先使用建一个简单类型

//声明一个函数,我们获取他的参数类型 string[] (假设其是一个复杂类型,或者我们获取不到)
const giveCount = (gifts: string[]): number => {
    return gifts.length;
};
//编写泛型函数,通过传递函数类型,获取参数类型,使用 infer 占位参数类型
//使用到 extends 编写类似的函数类型,让我们传递的函数类型属于这个类型,以此提取出自己需要的类型
type GenerateGiftType = T extends (gifts: infer R) => number ? R : any;
//调用编写好的泛型函数,传入函数类型(使用typeof获取函数的类型)
//这样获取到的GiftType就是 string[] 类型了,其他的也是一样
type GiftType = GenerateGiftType<typeof giveCount>;

实际案例,比上面略微复杂,prisma 中中有这么一个稍微复杂些的事务类型,我们有时需要传递该类型,因此获取出来方便使用

//prisma.$transaction 调用的 $transaction 函数如下所示,我们需要取出他的 client 类型,其没对外暴露
 //有这个一个复杂函数类型
$transaction(fn: (client: Omit, ITXClientDenyList>) => Promise, options?: {
    maxWait?: number;
    timeout?: number;
    isolationLevel?: TypeMap['meta']['txIsolationLevel'];
}): Promise;

我们使用 infer 将其取出来

//编写提取函数
type PrismaTransactionFunctionsType = T extends (
    fn: (prisma: infer P) => Promise,
) => Promise
    ? P
    : any
//调用提取函数,拿出类型
export type PrismaTransactionType = PrismaTransactionFunctionsType<
    typeof prisma.$transaction
>

断言 as、、!

这里断言意思就是直接认为指定内容是某种类型,如果实际执行时类型不是断言类型,仍然会报错,仅仅是根据特殊场景使用

// 尖括号<>断言类型,此外更多的是传入泛型参数使用
let unknowValue: any = "this is a string";
let len: number = (someValue).length;
// as 断言
let unknowValue: any = "this is a string";
let len: number = (someValue as string).length;

!也有断言意思,但是和上面的稍微不一样,这个是非空断言,强制执行的意思

let num: number | undefined | null
...
//此时执行时,确定了 num 是 number 类型,但是系统不识别
const length = num!.length //直接强制执行,认为非空即可

解构与展开

es6 中常见的解构和展开(...)是这样的

//数组
const list = [1, 2, 3];
//解构
const [x, y, z] = list; // [1, 2, 3]
//展开
let list2 = [...list, 4, 5] // [1 2 3 4 5]
//对象
const obj = {
    a: 1,
    b: 2,
    c: 3,
}
//解构
const {a, b, c} = obj
//展开
const obj2 = {
    ...obj,
    d: 4
}

函数剩余参数

除了上面的解构与展开,函数也有像展开的功能,这里挨着区分一下,其是剩余参数

先介绍下常见函数

//常见函数
function push() {}
const push = () => {}
//带参函数
functin push(item: string) {}
//带默认值函数
function push(item: string, isFinal = false) {}
//带可选参数函数,可选不传递就是undefined,且只能在最后
function push(item: string, specItem?: string) {}

下面介绍剩余参数

//支持传入多个参数,其是以数组的方式接收
function push(...items: T[]) {
    items.forEach(item => {})
    for (const item of items) {}
}
//假设前面有其他参数,加入剩余参数,剩余参数只能在末尾
function join(index: number, item: T, ...pushItems) {
}

“函数重载”

typescript 说是重载,实际上本身不存在重载这个东西(至少对比 c++ 这类不算),其只有函数重载类型,而不具备实际的函数重载功能,仅仅是一个提示,但是可以通过一个归一函数,将不同类型的参数区分开

以 typescript 声明重载类型,以实际函数根据不同参数类型的实现结合,最后形成另类函数重载,使用不是很友好,但未尝不是一种重载方案

//声明的几种类型
function add(a: number, b: number): number; 
function add(a: string, b: string): string; 
function add(a: string, b: number, c: boolean): string;
//实际实现的函数,参数必定是联合类型,需要根据参数区别作出相应处理
function add(a: string | number, b: string | number, c?: boolean) { 
    if (c !== undefined) {}
    else if (typeof a === "string") {} 
    else if (typeof a === 'number') {}
}

interface、type

他们两个功能类似

interface 为接口,主要针对 class、object、function 对象类型,很多语言中都有这种概念(接口、协议)

type 是类型别名,除了上面的,还针对更多类型,例如联合类型、元组、函数等,并且还支持更多类型操作,前面介绍的大多基本都是 type 的操作,就说重不重要吧

最后

typescript 还有非常多的内容,这里就介绍这么多,如果还需要了解更多,可以详细学习 typescript,前面有介绍参考地址

最后,希望大家有所收获,俺也一样