【TS基础】个人学习记录8-零碎概念之类型守卫、类型兼容、keyof、typeof、?与&、感叹号、注释、工具类型

类型守卫

在写函数的时候容易碰到一个这样的场景,输入不同类型的参数进去,函数内部做的一些逻辑只能针对某种变量类型,这时就需要用条件去做判断了:

// 例如:把一个字符串或者数组内的所有子项都转成大写
let convertToUpperCase = (strOrArray: string | string[]) => {
  if (typeof strOrArray === 'string') {
    return strOrArray.toUpperCase();
  } else if (Array.isArray(strOrArray)) {
    return strOrArray.map(item => item.toUpperCase());
  }
}

通过条件做类型的判断就是其中一种类型守卫

我们还可以通过switchtypeof===instanceof等等语句作类型守卫。

这里就专门讲下对付对象类型的守卫怎么写,用in关键字:

interface Dog {
  wang: string;
}
interface Cat {
  miao: string;
}

const getName = (animal: Dog | Cat) => {
    if ('wang' in animal) { 
      return animal.wang; 
    } else if ('miao' in animal) { 
      return animal.miao; 
    }
}

还需要提一个类型谓词 is

const isDog = function (animal: Dog | Cat): animal is Dog { // 通过is来指定看为Dog类型
  return "wang" in animal;
};
const getName = (animal: Dog | Cat) => {
  if (isDog(animal)) { // 然后这个函数还可以用在专门来判断联合类型中是否是具体某个类型
    return animal.wang;
  }
};

注意:此时的is不能用as类型断言来代替,会报错。


类型兼容

先跳过…


keyof

可以拿到interface的所有键,组成联合类型。

interface P{
    x: number;
    y: number;
}
type keys = keyof P; // 遍历出来  "x" | "y"

结合泛型约束可以实现个不错的功能,在符合ts要求下,通过输入对象和key:

function get<T extends object, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key]
}

拓展(看不懂也没关系,因为Ts已经给我们提供了工具类型):

interface User {
  id: number;
  age: number;
  name: string;
};

type Partial<T> = {  // 就是把接口内容都转成可选的
  [P in keyof T]?: T[P];
};
type PartialUser = Partial<User> // 相当于 = { id?: number; age?: number; name?: string; }
 
type Pick<T, K extends keyof T> = { // 就是单独拿出指定内容
  [P in K]: T[P];
};
type PickUser = Pick<User, "id" | "age">  // 相当于 = { id: number; age: number; }

typeof

和js的功能不一样,返回的是当前变量的类型

let obj = { a: '1' }
type A = typeof obj

?与 &&

const err = new Error();
err.stack.split('\n'); // 因为Error中的stack是个可选属性,所以这样直接使用ts会报‘对象可能为“未定义”。
// 使用?号
err.stack?.split('\n'); // 相当于 err.stack && err.stack.split('\n');

!用法

这里直接引用文章TypeScript中的问号 ? 与感叹号 ! 的含义的代码

重新定义属性特性:

// 因为接口B里面name被定义为可空的值,但是实际情况是不为空的,那么我们就可以
// 通过在class里面使用!,重新强调了name这个不为空值
class A implemented B {
  name!: string
}

interface B {
  name?: string
}

强制链式调用:

// 我们确信这个字段100%出现,那么就可以添加!,强调这个字段一定存在,ts不要对他进行类型校验了
new Error().stack!.split('\n');

注释

TS的注释可以让编辑器识别,然后通过按住ctrl键鼠标移入注释的关键字后就会有浮窗显示注释:

/** 这是一个人的接口定义 */
interface Person {
  /** 人的姓名 */
  name: string,
}

const p: Person = { // 按住ctrl键鼠标移入显示 “这是一个人的接口定义”
    name: 'cool' // 按住ctrl键鼠标移入显示 "人的姓名"
}

工具类型

ts提供了很多定义好的工具类型供我们使用,叫做utility type。下面积累几个例子。

Parameters

场景举例,在一个函数Fn1中你需要返回一个全新的函数Fn3,但是Fn3函数的入参类型是另外一个函数Fn2的入参类型,那么可以这样写:

Fn1 = () => {
	return (...[a, b]: Parameters<typeof Fn2>) => {] // typeof 表示获取Fn2的入参类型,然后通过泛型传入到Parameters中,Parameters就会帮我们提取Fn2的入参类型,作为...[a, b]入参的约束
}

typeof不是js的类型判断,是ts代码编写时期的类型获取,不会真正参与编译

Partial

场景举例,当我们定义了一个接口或者类型别名

type Person = {
	name: string,
	age: number,
	...
}

然后要用于一个变量的约束,但是这个变量只需要定义age,就可以用这个工具类型

let xiaoming: Partial<Person> = {age: 18} // 不会报错

一般都用于节省接口的部分重复定义。

当然,函数入参就不需要这个工具类型也能支持,具体可以看【TS基础】个人学习记录3-学习函数、箭头申明、参数、this、重载

不过这个Partial的功能就显得很不严格了,还是上面的例子,变量也可以直接赋值{},而且类型约束变得很随意,只要小于等于Person的内容即可。

所以,可以用另一个工具类型去解决。

Omit

场景举例,当我们定义了一个接口或者类型别名

type Person = {
	name: string,
	age: number
}

然后要用于一个变量的约束,但是这个变量只需要定义age,而且必须要严格限定类型不能和Partial一样,就可以用这个工具类型。

let xiaoming: Omit<Person, 'name'> = {age: 18} // 表示使用删除了name属性的Person作为约束

如果删除的接口属性比较多,可以这样子:

let xiaoming: Omit<Person, 'name' | 'age'> = {} // 表示使用删除了name,age属性的Person作为约束

Pick

场景举例,当我们定义了一个接口或者类型别名

type Person = {
	name: string,
	age: number
}

然后要用于一个变量的约束,但是这个变量只需要定义age,就可以用这个工具类型。

let xiaoming: Pick<Person, 'age'> = {age: 18} // 表示使用只提取了age属性的Person作为约束

也可以多个提取

let xiaoming: Pick<Person, 'age', 'name'> = {} 

Exclude

用于联合类型的内容剔除

type Person = {
	name: string,
	age: number
}
type P = keyof Person 
type Age = Exclude<P, 'name'> // 意思就是把联合类型里的name剔除了

Record

type TKeys = 'A' | 'B'

interface IInfo {
  name:string,
  age?: number,
}

type TRecord = Record<TKeys, IInfo>

// 等同于
type TRecord = {
  A: IPeople;
  B: IPeople;
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
keyof typeof用于获取一个对象类型的所有属性名的联合类型typeof操作符用于获取一个值的类型,而keyof操作符用于获取一个类型的所有属性名。因此,keyof typeof可以用于获取一个对象的所有属性名的联合类型。 举个例子,假设我们有一个对象person,其类型为Person: ``` type Person = { name: string; age: number; gender: string; }; const person: Person = { name: &quot;John&quot;, age: 30, gender: &quot;male&quot; }; ``` 我们可以使用keyof typeof来获取person对象的所有属性名的联合类型: ``` type PersonKeys = keyof typeof person; // PersonKeys的类型&#39;name&#39; | &#39;age&#39; | &#39;gender&#39; ``` 这样,我们就可以使用PersonKeys来限制一个函数的参数类型,以确保只能传入person对象的属性名作为参数。&lt;span class=&quot;em&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;em&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;em&quot;&gt;3&lt;/span&gt; #### 引用[.reference_title] - *1* *2* [typescript类型判断](https://blog.csdn.net/meng16/article/details/111404848)[target=&quot;_blank&quot; data-report-click={&quot;spm&quot;:&quot;1018.2226.3001.9630&quot;,&quot;extra&quot;:{&quot;utm_source&quot;:&quot;vip_chatgpt_common_search_pc_result&quot;,&quot;utm_medium&quot;:&quot;distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2&quot;}}] [.reference_item style=&quot;max-width: 50%&quot;] - *3* [TypeScript中的keyoftypeof、索引访问类型、条件类型](https://blog.csdn.net/jieyucx/article/details/131363515)[target=&quot;_blank&quot; data-report-click={&quot;spm&quot;:&quot;1018.2226.3001.9630&quot;,&quot;extra&quot;:{&quot;utm_source&quot;:&quot;vip_chatgpt_common_search_pc_result&quot;,&quot;utm_medium&quot;:&quot;distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2&quot;}}] [.reference_item style=&quot;max-width: 50%&quot;] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值