- 作者:老汪软件技巧
- 发表时间: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,前面有介绍参考地址
最后,希望大家有所收获,俺也一样