TypeScript中的keyof、typeof、索引访问类型、条件类型

这篇具有很好参考价值的文章主要介绍了TypeScript中的keyof、typeof、索引访问类型、条件类型。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、keyof类型操作符

TypeScript中的keyof类型操作符可以获取某个类型的所有属性名组成的联合类型。这个操作符的作用是帮助开发者在静态类型检查中更准确地操作属性名。

举例来说,如果我们有如下一个接口:

interface Person {
  name: string;
  age: number;
  gender: 'male' | 'female';
}

我们可以使用keyof来获取这个接口的属性名联合类型:

type PersonKeys = keyof Person;
// 等价于:
// type PersonKeys = 'name' | 'age' | 'gender'

有了属性名联合类型,我们可以在编写代码时更准确地操作属性名。以下是一些使用keyof的实际应用:

1. 动态获取对象的属性值

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

const person: Person = { name: 'Lucy', age: 18, gender: 'female' };
const name = getProperty(person, 'name'); // 类型为string
const age = getProperty(person, 'age'); // 类型为number
const gender = getProperty(person, 'gender'); // 类型为'male' | 'female'

在这个例子中,getProperty函数的第一个参数是一个泛型类型的对象,第二个参数是对象的属性名。由于我们使用了keyof,所以在编写代码时我们可以确定属性名的类型,并且编译器也可以在编译时进行类型检查,保证我们不会误操作属性名或者试图访问不存在的属性。

2. 限制对象的属性种类

function createUser<Keys extends keyof Person>(name: string, value: Person[Keys]): Person {
  const user: Person = { name, age: 0, gender: 'male' };
  user[key] = value; // 编译器知道key是Person的属性名之一,不会有任何错误
  return user;
}

const newUser = createUser('Tom', 'male'); // 类型为Person
const errorUser = createUser('Jack', 'unknown'); // 编译错误

在这个例子中,createUser函数通过泛型限制了属性名的类型,而属性名的类型只能从Person的属性名中取值。在函数内部,我们可以安全地使用key来访问person对象的属性,因为key的类型是Person的属性名之一。如果我们试图传入一个不合法的属性名,编译器会及时提示错误。

3. 避免硬编码属性名

class User {
  constructor(private data: Person) {}

  get<K extends keyof Person>(key: K): Person[K] {
    return this.data[key];
  }
}

const user = new User({ name: 'Lucy', age: 18, gender: 'female' });
const name = user.get('name'); // 类型为string
const age = user.get('age'); // 类型为number
const gender = user.get('gender'); // 类型为'male' | 'female'

在这个例子中,User类接受一个Person对象作为构造函数的参数,同时提供了一个get方法来获取属性值。我们使用了泛型和keyof,这样在代码中就不需要硬编码属性名,避免了潜在的错误。泛型的约束可以帮助我们在编译时确保只能传入合法的属性名。

二、typeof类型操作符

TypeScript中的typeof类型操作符可以用来获取一个值的类型信息,它返回一个代表该值类型的字符串。typeof操作符不会运行代码,只会在编译时进行类型检查。

使用typeof类型操作符的场景包括:

1. 类型检查:可以用来检查变量的类型。例如,可以使用typeof操作符来检查变量是不是一个字符串。

let str = 'hello world';
if (typeof str === 'string') {
  console.log('str is a string');
}

2. 类型推断:可以使用typeof来推断函数返回值的类型。

function double(num: number): number {
  return num * 2;
}

let num = 10;
let numDouble = double(num); // numDouble的类型被推断为number

if (typeof numDouble === 'number') {
  console.log('numDouble is a number');
}

3. 编写工具函数:可以使用typeof来编写工具函数,比如判断一个值是不是一个数组。

function isArray(value: any): value is Array<any> {
  return typeof value === 'object' && value !== null && Array.isArray(value);
}

let arr = [1, 2, 3];
if (isArray(arr)) {
  console.log('arr is an array');
}

4. 简化重复代码:可以使用typeof来简化重复代码,比如初始化一个对象中的属性值。

interface Person {
  name: string;
  age: number;
}

function createPerson(name: string, age: number): Person {
  return {
    name,
    age,
    id: typeof name === 'string' ? name.slice(0, 3).toUpperCase() + age.toString() : '',
  };
}

let person = createPerson('John', 30);
console.log(person.id); // JOH30

总之,typeof类型操作符在TypeScript中有很多用途,可以帮助开发者更好地编写类型安全的代码。

三、索引访问类型

索引访问类型在TypeScript中是一种用于获取类型中属性或元素的方式,它通过字符串或数字索引来访问具有下标的类型。它通常用于动态访问对象属性、数组元素和元组元素等。下面我们从多个角度介绍索引访问类型并举例说明。

1. 动态访问对象属性

假设我们有一个Person对象类型,它有两个属性name和age。我们可以通过索引访问类型来动态获取对象的属性值。

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

type Name = Person['name']; // string
type Age = Person['age']; // number

const person: Person = { name: 'John', age: 18 };

function getProperty(obj: Person, key: keyof Person) {
  return obj[key];
}

const name: string = getProperty(person, 'name'); // 'John'
const age: number = getProperty(person, 'age'); // 18

在上述代码中,我们定义了一个Person类型,并使用Person[‘name’]和Person[‘age’]来获取分别获取name和age的类型。我们使用keyof Person类型指定getProperty方法中的key参数只能传递Person对象的属性名。最后我们通过getProperty方法动态获取person对象的属性值。

2. 动态访问数组元素

索引访问类型也可以用于动态访问数组元素。我们可以通过索引类型来获取数组元素的类型,也可以通过keyof Array类型来获取数组的索引类型。

const fruits = ['apple', 'banana', 'orange'];

type Fruit = typeof fruits[number]; // 'apple' | 'banana' | 'orange'
type Index = keyof typeof fruits; // number | "length" | "toString" | "toLocaleString" | "push" | "pop" | "concat" | "join" | "reverse" | "shift" | "slice" | "sort" | "splice" | "unshift" | "indexOf" | "lastIndexOf" | "every" | "some" | "forEach" | "map" | "filter" | "reduce" | "reduceRight" | "entries" | "forEach" | "keys" | "values"

上述代码中,我们定义了一个数组fruits,并使用typeof fruits[number]和keyof typeof fruits分别获取了它的元素类型和索引类型。

3. 动态访问元组元素

元组是一种特殊的数组类型,其元素类型可以不同。我们可以通过索引访问类型来动态访问元组元素。

type Tuple = [string, number];

type First = Tuple[0]; // string
type Second = Tuple[1]; // number

const tuple: Tuple = ['hello', 123];

function getTupleElement<T extends ReadonlyArray<any>, U extends keyof T>(
  tuple: T,
  index: U,
): T[U] {
  return tuple[index];
}

const first: string = getTupleElement(tuple, 0); // 'hello'
const second: number = getTupleElement(tuple, 1); // 123

在上述代码中,我们定义了一个元组类型Tuple,通过Tuple[0]和Tuple[1]分别获取了它的第一个和第二个元素类型。同时,我们定义了一个getTupleElement方法,使用泛型T和U分别表示元组类型和索引类型,并通过T[U]获取元组指定索引处的元素。

总之,索引访问类型可以用于动态访问对象属性、数组元素和元组元素。它可以方便地处理动态类型,增强了TypeScript的灵活性和适用性。

四、条件类型

TypeScript中的条件类型可以根据某个类型的特定属性或条件,选择不同的类型。条件类型是TypeScript高级类型中的一种,可以用于定义泛型的约束条件,从而增强代码的类型安全性和灵活性。

下面从不同角度举例分析说明TypeScript中的条件类型:

1. 根据属性判断是否可选

条件类型可以根据某个属性是否存在或者是否可选来确定不同的类型。例如,以下代码中,当T中的K属性为可选属性时,返回Partial类型;当K为必选属性时,返回T本身:

type MyType<T, K extends keyof T> = K extends keyof T ? Partial<T> : T;

2. 根据属性值判断是否满足条件

条件类型可以根据某个属性的值是否满足条件来确定不同的类型。例如,以下代码中,当T中的K属性的类型为U时,返回T本身;否则返回never类型:

type MyType<T, K extends keyof T, U> = T[K] extends U ? T : never;

3. 根据类型之间的关系判断是否满足条件

条件类型可以根据不同类型之间的关系来确定不同的类型。例如,以下代码中,当T为U的子类型时,返回T本身;否则返回never类型:

type MyType<T, U> = T extends U ? T : never;

4. 根据函数参数类型判断返回值类型

条件类型可以根据函数参数的类型来确定函数返回值类型。例如,以下代码中,当T为函数类型时,返回函数返回值的类型;否则返回never类型:

type MyType<T> = T extends (...args: any[]) => infer R ? R : never;

5. 根据对象类型判断是否有特定属性

条件类型可以根据对象类型中是否含有特定属性来确定不同的类型。例如,以下代码中,当T中含有名为K的属性时,返回T本身;否则返回never类型:

type MyType<T, K> = keyof T extends K ? T : never;

通过以上几个例子,可以看出条件类型在TypeScript中的灵活性和强大的约束能力。条件类型可以根据不同的情况进行不同的判断,从而增强代码的可读性和可维护性。

五、类型推理infer

在TypeScript中,类型推理是一种自动推断变量类型的机制,它可以根据变量的使用上下文以及其值的类型来推断变量的类型。而infer关键字是TypeScript的一种高级类型操作符它可以用来从已知类型中推断出未知类型,让类型推理更加灵活

infer关键字通常在条件类型中使用,其中条件类型可以根据条件来决定返回的类型。infer用于捕获条件类型中的未知类型,然后可以用该类型来进行操作。下面分别从多角度举例说明infer如何使用。

1. 从函数参数中推断类型

在下面的这个例子中,我们可以看到如何使用infer关键字从函数参数中推断出其类型:

type ParameterType<T extends (...args: any) => any> = T extends ((arg: infer P) => any) ? P : never;

function foo(param: string) {}

type ParamType = ParameterType<typeof foo>; // string

在这个例子中,我们定义了一个ParameterType类型,它接受一个函数类型作为参数。然后,我们使用infer关键字来推断函数类型的参数类型,并将此类型指定为类型别名ParamType的值。

2. 从数组或元组中推断类型

在下面的这个例子中,我们可以看到如何使用infer关键字从数组或元组中推断出其类型:

type ArrayType<T> = T extends Array<infer U> ? U : never;
type TupleType<T> = T extends [infer U, ...infer V] ? [U, ...V] : never;

type A = ArrayType<number[]>; // number
type B = TupleType<[string, number, boolean]>; // [string, number, boolean]

在这个例子中,我们定义了两个类型别名ArrayType和TupleType。ArrayType接受一个数组类型作为参数,使用infer关键字推断出数组元素的类型,并将其作为其返回类型。TupleType接受一个元组类型作为参数,使用infer关键字推断出元组中第一个元素的类型,并使用剩余类型推断出元组剩余的元素类型。然后,我们分别将这些类型应用于变量A和变量B,得到相应的类型结果。

3. 从Promise中推断类型

在下面的这个例子中,我们可以看到如何使用infer关键字从Promise中推断出其类型:

type PromiseType<T> = T extends Promise<infer U> ? U : never;

async function foo(): Promise<string> {
  return 'hello';
}

type FooType = PromiseType<ReturnType<typeof foo>>; // string

在这个例子中,我们定义了一个PromiseType类型,它接受一个Promise类型作为参数,使用infer关键字推断出Promise的值类型,并将其作为其返回类型。然后,我们定义了一个异步函数foo,其返回类型为Promise。最后,我们将函数foo的ReturnType应用于PromiseType类型,并得到其返回值类型为string的结果。

总之,infer是TypeScript中一个非常重要的高级类型操作符,可以用于从已知类型中推断出未知类型,让类型推理更加灵活。通过上述多个角度的示例,希望可以更好地理解infer在TypeScript中的实际应用。

六、分布式条件类型

分布式条件类型是TypeScript的一项高级特性,它也是条件类型的一种。分布式条件类型可以根据一个类型参数 T,在联合类型中判断 T 是否为其他类型,并根据 T 是该类型或其子集来生成新类型。这个生成过程会在联合类型中遍历每一个元素,并生成对应的类型。与普通的条件类型不同的是,分布式条件类型会把联合类型的操作分发到每一个元素中。

下面我们通过举例分析,更全面地了解分布式条件类型。

1、 基本使用

首先,我们看一个最基本的例子:

type IfNumber<T> = T extends number ? 'yes' : 'no';
type A = IfNumber<1>; // 'yes'
type B = IfNumber<'a'>; // 'no'
type C = IfNumber<number | string>; // 'yes' | 'no'

这里,我们定义了一个条件类型IfNumber,当T是number类型的时候返回’yes’,否则返回’no’。当我们分别传入1、‘a’、number | string三种类型作为类型参数进行测试时,分别返回’yes’、‘no’、‘yes’ | ‘no’。

2、 分布式条件类型在泛型中的应用

分布式条件类型可以用在泛型中,作为泛型约束的一部分。比如,我们可以定义一个函数,用于获取对象的属性值。如果对象的属性值是数字,返回数字类型的对象,否则返回字符串类型的对象。

type ObjectValue<T> = T extends { [key: string]: infer U } ? U : never;
type ObjectWithType<T, U> = { [K in keyof T]: ObjectValue<T[K]> extends U ? T[K] : never };
type ExtractObject<O, U> = ObjectWithType<O, U>[keyof O];

function getPropByType<O, U>(obj: O, type: U): ExtractObject<O, U>[] {
  const result = [];
  for (const key in obj) {
    const value = obj[key];
    if (typeof value === typeof type) {
      result.push(value);
    }
  }
  return result;
}

const obj = {
  a: 1,
  b: '2',
  c: 3,
};
const result = getPropByType(obj, '2');

这里,我们使用分布式条件类型ObjectWithType来定义一个新类型ObjectWithType<T, U>,它可以将T中每个属性值的类型做比较,只有当属性值的类型===U时才保留该属性。同时,我们使用ObjectValue来辅助获取对象属性值的类型。在getPropByType函数中,我们传入一个对象和一个类型参数U,函数会遍历对象的属性值,检查它们的类型是否等于U,并将符合条件的属性值保存在数组中后返回。

3、 分布式条件类型在类型映射中的应用

分布式条件类型还可以用于类型映射中。下面我们使用分布式条件类型,实现一个将对象中所有属性变成可选属性的函数。

type Optionalize<T> =
  T extends any ? {
    [K in keyof T]?: Optionalize<T[K]>;
  } : never;

function optionalize<Key extends string, O extends { [K in Key]: any }>(obj: O): Optionalize<O> {
  const result: Optionalize<O> = {};
  for (const key in obj) {
    const value = obj[key];
    if (typeof value === 'object' && !Array.isArray(value)) {
      result[key] = optionalize(value);
    } else {
      result[key as keyof O] = value;
    }
  }
  return result;
}

const obj = {
  a: {
    b: 1,
    c: {
      d: 2,
    },
  },
  e: '3',
};
const optionalObj = optionalize(obj);

这里,我们使用了分布式条件类型来定义Optionalize类型。它首先认为T可以是任何类型,然后对于T中的每个属性K,我们都将它变成一个可选属性。在optionalize函数中,我们分别遍历了obj的所有属性,并根据value的类型决定是递归处理还是复制value的值到result中,最终返回了一个可选属性合集Optionalize。

分布式条件类型是一项高级特性,它可以对联合类型的所有元素进行操作,生成多样化的新类型。我们在实际场景中可以通过它来解决一些复杂的问题,比如提取对象中某个类型的属性、将对象中的属性转换成可选属性。掌握这个知识点,可以让我们更好地应对类型转换的挑战。文章来源地址https://www.toymoban.com/news/detail-505934.html

到了这里,关于TypeScript中的keyof、typeof、索引访问类型、条件类型的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • TypeScript 学习笔记(七):条件类型

    TS中的条件类型就是在类型中添加条件分支,以支持更加灵活的泛型,满足更多的使用场景。内置条件类型是TS内部封装好的一些类型处理,使用起来更加便利。 当T类型可以赋值给U类型时,则返回X类型,否则返回Y类型。 T U X Y 四个是占位符,分别表示四种类型; T extends U

    2024年02月17日
    浏览(39)
  • TypeScript 学习笔记(六):索引签名类型、映射类型

    keyof 可以用于获取某种类型的所有键,其返回类型是联合类型。 keyof 与 Object.keys 略有相似,只不过 keyof 取 interface 的键 通过例子可以看到,这里的keyof Info其实相当于\\\"name\\\" | “age”。通过和泛型结合使用,TS 就可以检查使用了动态属性名的代码: 接口 基本数据类型 类 如果

    2024年02月17日
    浏览(43)
  • 【前端进阶】-TypeScript高级类型 | 交叉类型、索引签名类型、映射类型

    前言 博主主页👉🏻蜡笔雏田学代码 专栏链接👉🏻【TypeScript专栏】 上篇文章讲解了TypeScript部分高级类型 详细内容请阅读如下:🔽 【前端进阶】-TypeScript高级类型 | 类的初始化、构造函数、继承、成员可见性 今天来学习TypeScript另外一些高级类型! 感兴趣的小伙伴一起来

    2023年04月08日
    浏览(35)
  • typescript typeof操作符

    在TypeScript中,typeof是一个操作符,用于获取一个值的类型。它可以与任何值一起使用,并返回一个描述该值类型的字符串。 typeof操作符在TypeScript中的用法与JavaScript中的用法非常相似。 如下,众所周知,在js中提供了typeof 操作符用来在js中获取数据的类型 tpyescript 中的typeof操作

    2024年02月22日
    浏览(30)
  • 前端TypeScript学习day05-索引签名、映射与类型声明文件

    (创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹)              目录 索引签名类型  映射类型 索引查询(访问)类型 基本使用  同时查询多个索引的类型  TypeScript 类型声明文件  概述 TS 的两种文件类型  类型声明文件的

    2024年02月08日
    浏览(47)
  • typeScript中的函数类型

    目录 1.函数声明 2.函数表达式 3.用接口定义函数的形状 4.可选参数 5.参数默认值  6.剩余参数 7.重载 函数是JavaScript应用程序的基础。它帮助你实现抽象层, 模拟类,信息隐藏和模块。在TypeScript里, 虽然已经支持类,命名空间和模块,但函数仍然是主要的定义行为的地方。

    2024年02月03日
    浏览(38)
  • TypeScript 中的字面量类型和联合类型特性

    字面量类型和联合类型是 TypeScript 中常用的类型特性。 1. 字面量类型: 字面量类型是指具体的值作为类型。例如,字符串字面量类型可以通过给定的字符串字面量来限制变量的取值范围。 2. 联合类型: 联合类型可以用来表示一个变量可以是多个类型中的任意一个。使用 |

    2024年02月15日
    浏览(41)
  • TypeScript 中的常用类型声明大全

    上一章节,我们介绍了什么是TS,以及TS的应用场景。本章节将给大家介绍,在TypeScript 中,常用的数据类型声明,有我们熟悉的 基本数据类型,也有,一些TypeScript 新增的一些,语法规范类型。出发吧… 函数:同样的,也可以给函数限制 接受形参的类型和,限制返回值的数

    2024年02月16日
    浏览(37)
  • TypeScript中的类型声明declare

    在 TypeScript 中, declare 用于定义 全局 变量、函数和类型等 ,提供了一种在编译过程中告诉TypeScript编译器某个标识符的类型的方式。它告诉编译器:虽然它在当前文件中没有声明,但它在其他地方已经存在了。也就是说,declare让 编译器 知道 这些声明的实体是在编译

    2024年02月12日
    浏览(47)
  • TypeScript 中的类型检查实用函数

    在前端开发中,我们经常需要判断变量的类型以进行相应的操作或处理。TypeScript 提供了基础的类型检查,但有时我们需要更复杂或更灵活的类型检查。这篇博客文章将介绍一组实用函数,用于各种常见的类型检查。

    2024年02月10日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包