More advanced types with TypeScript generics

栏目: IT技术 · 发布时间: 4年前

内容简介:Previously, we’ve discussedGenerics are very useful in many situations. By usingA

Previously, we’ve discussed the basics of TypeScript Generics . This time, we take them to a higher level. In this article, we learn about index types . To do so, we also explore  union types , the  keyof  keyword, and  string literal types . Today we also learn  mapped types and use them with  conditional types.

Index types

Generics are very useful in many situations. By using index types, we can improve our types even further. To get to know them, let’s first learn what a union type and the keyof keyword are.

A union type represents one of several types. To separate them, we use a vertical bar.

const value: string | number;

String literal typesare often used with unions. A string literal can only be assigned a particular string value. It can be considered a subtype of a string type.

type UserRole = 'admin' | 'moderator' | 'author';

Now, let’s consider this simple interface:

interface User {
  id: number;
  name: string;
  email: string;
  role: UserRole;
}

By using the keyof keyword, we can achieve a union of string literal types.

type UserKeysType = keyof User; // 'id' | 'name' | 'email' | 'role' ;

All of the above knowledge gives us quite a bit of flexibility.

Introducing index types

TypeScript 2.1 introduced index types . They look the same as accessing a property of an object but refer to types.

type IdType = User['id']; // number

We sometimes refer to index types as lookup types .

We can use the above in a dynamic manner. Let’s inspect this popular example:

const user: User = {
  id: 15,
  name: 'John',
  email: 'john@smith.com',
  role: 'admin'
};
function getProperty<ObjectType, KeyType extends keyof ObjectType>(
  object: ObjectType,
  property: KeyType
): ObjectType[KeyType] {
  return object[property];
}

When we use our getProperty , the compiler checks if a string that we pass into it is an actual property of an object.

getProperty(user, 'property');
Argument of type ‘”property”‘ is not assignable to parameter of type ‘”id” | “name” | “email” | “role”‘.

When we return object [ property ] , the TypeScript compiler performs a type lookup. Thanks to that, the return type of the  getProperty varies based on the passed string.

getProperty(user, 'id').toLowerCase();
Property ‘toLowerCase’ does not exist on type ‘number’.

Creating a Map from an object

A real-life example of the above might be converting an object to a Map. TypeScript aside, the most straightforward way to do this is to use Object.entries .

const settings = {
  isModalOpened: true,
  canDelete: false,
  role: 'Admin'
}
 
const settingsMap = new Map(
  Object.entries(settings)
);

The above code, even though valid, does not produce the most detailed types.

settingsMap.get('role').toLowerCase()
Property ‘toLowerCase’ does not exist on type ‘string | boolean’.

The error above indicates that the return type of the settingsMap . get function is a union type  'string | boolean' . We know that the type of  role is a string. Let’s fix that!

We can create our own interface that extends Map and provides more detailed typings.

interface MapFromObject<ObjectType, KeyType extends keyof ObjectType> extends Map<KeyType, ObjectType[KeyType]> {
  get: <PropertyType extends keyof ObjectType>(key: PropertyType) => ObjectType[PropertyType];
}
const settingsMap = new Map(
  Object.entries(settings)
) as MapFromObject<Settings, keyof Settings>;

Now, every time we use the get method, we get an exact type of property.

settingsMap.get('role').toLowerCase(); // 'admin'
If you have some other solution to the above issue, feel free to share it

If you need, you can also provide types for the set function in a similar manner.

Mapped types

The mapped types allow us to create new types from existing ones. A common use case is to make all of the properties of an object read-only .

type Readonly<ObjectType> = {
  readonly [KeyType in keyof ObjectType]: ObjectType[KeyType];
}

The above is such a common use-case that we now have a Readonly type built-in and ready to use.

An example of its usage is the Object.freeze function. Let’s look into how TypeScript handles it:

interface ObjectConstructor {
  /**
   * Prevents the modification of existing property attributes and values,
   * and prevents the addition of new properties.
   * @param o Object on which to lock the attributes.
   */
  freeze<T>(o: T): Readonly<T>;
}

As we can see, the Object.freeze function returns the object that is mapped using the Readonly modifier.

TypeScript developers identified more useful modifiers that might come in handy, such as Pick .

/**
 * From T, pick a set of properties whose keys are in the union K
 */
type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};

Even though we have a set of modifiers for different occasions, we might need to write some custom ones. When doing so, conditional types might be of some use.

Conditional type selects one of two types based on a condition
type WithNumbersInsteadOfStrings<ObjectType> = {
  [PropertyType in keyof ObjectType]: ObjectType[PropertyType] extends number ? string : ObjectType[PropertyType];
};
const user: WithNumbersInsteadOfStrings<User> = {
  id: '15',
  name: 'John',
  email: 'john@smith.com',
  role: 'admin'
};

Summary

In this article, we’ve expanded more on the subject of generics in TypeScript. We’ve investigated the indexed types and mapped types. When doing so, we’ve also learned the keyof  keyword, the union types . We’ve also stumbled upon  string literal types and  conditional types . Learning all of the above will definitely expand our TypeScript knowledge!


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Web API的设计与开发

Web API的设计与开发

[日] 水野贵明 / 盛荣 / 人民邮电出版社 / 2017-6 / 52.00元

本书结合丰富的实例,详细讲解了Web API的设计、开发与运维相关的知识。第1章介绍Web API的概要;第2章详述端点的设计与请求的形式;第3章介绍响应数据的设计;第4章介绍如何充分利用HTTP协议规范;第5章介绍如何开发方便更改设计的Web API;第6章介绍如何开发牢固的Web API。 本书不仅适合在工作中需要设计、开发或修改Web API的技术人员阅读,对想了解技术细节的产品经理、运维人......一起来看看 《Web API的设计与开发》 这本书的介绍吧!

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具