TypeScript详解十三:内置工具类型


前言

TS为了方便开发者使用,在内部提供了非常多的工具类型,如Partial、Required、ReadOnly等等,本篇文章主要用于记录了一些常用的内置工具类型的使用及源码实现,以便参考。


提示:以下是本篇文章正文内容,下面案例可供参考

一、什么是ts内置工具类型

TypeScript 附带了大量类型,可以帮助进行一些常见的类型操作,通常称为 Utility Types。

二、使用示例

1.Partial

  • 将必填参数变为可选参数
namespace a {
  // 示例一:
  interface A {
    name: string,
    age: number,
    sex: string
  }
  // 接口A中的参数通过内置工具类型Partial变成了可选参数
  type PartialA = Partial<A>;
  let a: PartialA = {
    // 此处传参可以任意个数,但只能传已定义的参数
    name: '张三',
    age: 10
  }

  // 示例二:
  interface Company {
    id: number,
    name: string
  }
  interface Person {
    id: number,
    name: string,
    company: Company
  }
  // 实现DeepPartial,将参数深度转换成可选参数
  type DeepPartial<T> = {
    [U in keyof T]?: T[U] extends object ? DeepPartial<T[U]> : T[U];
  }
  type PartialPerson = DeepPartial<Person>;
  let p: PartialPerson = {
    // 此处的参数已经变为可选参数,可根据自己需要传递
    id: 10,
    name: '张三',
    company: {
      name: '美团'
    }
  }
}
  • Partial的实现源码
namespace b {
  interface A {
    name: string,
    age: number,
    sex: string
  }
  type Partial<T> = {
    // 原理:
    // 1.通过keyof拿到T中的所有key
    // 2.迭代所有的key
    // 3.统一加上可选参数处理
    // 4.返回迭代值的类型
    [P in keyof T]?: T[P];
  }

  // 测试:
  type PartialA = Partial<A>;
  let a: PartialA = {
    name: '张三',
    age: 10
  }
}

2.Required

  • 将所有参数变为必填
namespace b {
  interface Person {
    name: string,
    age?: number
  }
  // Required将可选参数变为必填
  type RequiredPerson = Required<Person>;
  let person: RequiredPerson = {
    name: '张三',
    age: 10
  }
}
  • Required 的实现源码
namespace c {
  interface Person {
    name: string,
    age?: number
  }
  type Required<T> = {
    // 原理:
    // 1.通过keyof拿到T中所有的key
    // 2.迭代所有的key
    // 3.将可选的参数变为必填的参数
    // 4.返回迭代属性及类型
    // +?或者?: 代表的是可选,-?: 代表的是不可选
    [P in keyof T]-?: T[P];
  };

  // 测试
  type RequiredPerson = Required<Person>;
  let person: RequiredPerson = {
    name: '李四',
    age: 18
  }
}

3.ReadOnly

  • 将所有参数变为只读
namespace d {
  interface Person {
    name: string,
    age?: number
  }
  type ReadonlyPerson = Readonly<Person>;
  let person: ReadonlyPerson = {
    name: '张三',
    age: 10
  }
  // 已经变为只读属性,因此此处赋值会报错
  // person.name = '李四'; // 无法分配到 "name" ,因为它是只读属性。ts(2540)
  // person.age = 20; // 无法分配到 "age" ,因为它是只读属性。ts(2540)
}
  • Readonly 的实现源码
namespace e {
  interface Person {
    name: string,
    age?: number
  }
  type Readonly<T> = {
    // 原理:
    // 1.通过keyof拿到T中所有key
    // 2.迭代拿到的所有key
    // 3.通过readonly关键字将所有属性变为只读属性
    // 4.返回迭代属性及类型
    readonly [P in keyof T]: T[P]
  }

  // 测试
  type ReadonlyPerson = Readonly<Person>;
  let person: ReadonlyPerson = {
    name: '张三',
    age: 10
  }
  // person.name = '李四'; // 无法分配到 "name" ,因为它是只读属性。ts(2540)
  // person.age = 20; // 无法分配到 "age" ,因为它是只读属性。ts(2540)
}

4.Pick

  • 捡取符合条件的属性
namespace g {
  interface Person {
    name: string,
    age: number,
    sex: string
  }

  // 参数一是一个对象,参数二是要筛选的属性
  type PickPerson = Pick<Person, 'name' | 'sex'>;
  let person: PickPerson = {
    name: '张三',
    // 由于通过Pick只捡取了name和sex属性,因此此时给sex赋值会报错
    // 不能将类型“{ name: string; age: number; sex: string; }”分配给类型“PickPerson”。
    // 对象文字可以只指定已知属性,并且“age”不在类型“PickPerson”中。ts(2322)
    // age: 10,
    sex: '男'
  }
}
  • Pick 的实现源码
namespace h {
  interface Person {
    name: string,
    age: number,
    sex: string
  }
  // 原理:
  // 1.T表示传入的类型定义。此处指Person接口。
  // 2.K表示T的子类型,是一个联合类型。此处指'name' | 'age' | 'sex'的子类型
  // 3.通过keyof拿到T中的所有key
  // 3.迭代K,拿到所有传递进来的子类型
  // 4.返回迭代属性及类型
  // 简单理解:就是从一个对象中,提取一部分属性组成新的对象
  type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
  }

  // 测试
  type PickPerson = Pick<Person, 'name' | 'age'>
  let person: PickPerson = {
    name: '张三',
    age: 10
  }
}

5.Record

  • 记录类型:将一个类型的所有属性值都映射到另一个属性上并创建新的类型
namespace i {
  // 1.此处的K主要用来修饰obj对象的key,为string或者number
  // 2.此处的T用来修饰老的类型
  // 3.此处的U用来修饰新的类型
  function mapObj<K extends string | number, T, U>(obj: Record<K, T>, callable: (x: T) => U) {
    // 声明一个变量
    let result: Record<K, U> = <Record<K, U>>{};
    // 遍历传入的对象
    for (const key in obj) {
      // 通过callback函数处理result的属性值
      result[key] = callable(obj[key]);
    }
    // 返回result
    return result;
  }
  let obj = { num1: 1, num2: 2 };
  let callable = (x: number): string => x * 2 + '';
  let newObj = mapObj<string | number, number, string>(obj, callable);
  console.log(newObj); // { num1: '2', num2: '4' }
}
  • Record 的实现源码
namespace j {
  type Record<K extends keyof any, T> = {
    // 原理:
    // 1.通过keyof拿到所有的K,是一个联合类型。string | number | symbol
    // 2.迭代K,拿到所有的属性
    // 3.返回迭代的属性及类型
    // 注意:此处不能写成 type Record<K, T> = {}; any代表所有key的联合类型。
    // 否则会报错:不能将类型“K”分配给类型“string | number | symbol”。ts(2322)
    [P in K]: T;
  };

  // 测试
  function mapObj<K extends string | number, T, U>(obj: Record<K, T>, callable: (x: T) => U) {
    // 声明一个变量
    let result: Record<K, U> = <Record<K, U>>{};
    // 遍历传入的对象
    for (const key in obj) {
      // 通过callback函数处理result的属性值
      result[key] = callable(obj[key]);
    }
    // 返回result
    return result;
  }
  let obj = { num1: 1, num2: 2 };
  let callable = (x: number): string => x * 2 + '';
  let newObj = mapObj<string | number, number, string>(obj, callable);
  console.log(newObj); // { num1: '2', num2: '4' }
}

总结

本篇文章只记录了这几种内置工具类型,更多内置类型可前往https://www.typescriptlang.org/docs/handbook/utility-types.html查看。下次再见

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
TypeScript提供了许多内置工具类,用于增强类系统的功能。其中一些常用的工具类包括: 1. Partial<Type>: 将类中的所有属性都设置为可选的。这样可以方便地创建只包含部分属性的对象。 2. Required<Type>: 将类中的所有属性都设置为必需的。这样可以确保对象中的所有属性都被赋值。 3. Readonly<Type>: 将类中的所有属性都设置为只读的。这样可以防止对对象的属性进行修改。 4. Record<Key, Type>: 创建一个由指定键和值类组成的对象类。可以用于创建字典或映射类。 5. Pick<Type, Keys>: 从类中选择指定的属性。返回一个新的类,只包含指定的属性。 6. Omit<Type, Keys>: 从类中排除指定的属性。返回一个新的类,不包含指定的属性。 7. Exclude<Type, ExcludedUnion>: 从类中排除指定的联合类。返回一个新的类,不包含指定的联合类。 8. Extract<Type, Union>: 从类中提取指定的联合类。返回一个新的类,只包含指定的联合类。 9. NonNullable<Type>: 从类中排除 null 和 undefined。返回一个新的类,不包含 null 和 undefined。 10. ReturnType<Type>: 获取函数类的返回值类。 11. InstanceType<Type>: 获取构造函数类的实例类。 12. ThisType<Type>: 用于指定 this 关键字的类。可以在函数签名或对象字面量中使用,以指定 this 关键字的类为该类。 这些工具类可以帮助我们更好地定义和操作类,提高代码的可读性和可维护性。[3]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

剑九 六千里

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值