link
Good evening, everyone. I’m doing this for you, because several teams are starting to use TypeScript now. In addition to working with TypeScript on a regular basis, I’d like to give you some tips on how to get started with generics.
So let’s talk about what generics are in terms of why they exist. Let’s look at this code. We define an identity function that handles data of type number and returns data of type number. Again to see the next piece of code, when the function to deal with the other types, we have to define the other types, such as adding string on the basis of the number | Array < string > type and so on, of course, that is to use the concept of function overloading, but I’m here is abruptly leads to generics.
Finally we see this code, which we can use automatically with TypeScript type inference, or we can pass in a type to define the type we want, such as identity< Boolean >(true), which is generic.
I’ve given you an excerpt of the official global generics provided by Utility Types.
These official generics are very easy to use, and people use a lot in daily development, so how to write your own generics? Starting here will be the focus of this sharing.
Let’s look at example 1, where isString doesn’t have typeof Value === ‘string’ makes sense, because isString can’t do type inference, and some of you might say, WELL, I’m going to use an assertion on EL, which is fine from a code run point of view. But with TypeScript, you should make type inference more natural, rather than using assertions to solve problems. How is that any different from writing JavaScript? So it’s really easy, let’s change the Boolean that the function returns to value is String so we can do type inference.
Isn’t that interesting, and going a step further, is there something we can do to change this isString function to make it more generic?
declare function isSomething <T> (value: T) :value is T
const num = isSomething(1) / /isSomething<number>
const str = isSomething(' ') / /isSomething<string>
Copy the code
It’s wonderful, isn’t it? In example 2, if we want to write a style object, but we need to consider compatibility, such as adding the prefix Webkit, then we will naturally write them out one by one, but there are a lot of complicated problems in maintaining the type. For example, when I change the type of Flex, I also need to modify the corresponding types of webKit prefixes, and as this scenario becomes more and more complex, the maintenance cost of the code increases.
Of course there are ways to solve this problem, first we need to use some means to convert Flex to webkitFlex, and then change the interface key to what we want.
So far, we have been able to achieve the key replacement, but the original key is missing, so we need use | P to complete here, to achieve our requirements. So far we’ve done what we want to do, so let’s take it a step further, just to make things interesting, and we want to convert lineHeight without webKit prefix, so how do we do that?
type WebkitKey<K extends string> = K extends 'lineHeight' ? never : `webkit${Capitalize<K>}`
Copy the code
In this way, we can implement the new requirements, but of course we can also use example 1 to further the requirements.
type ExcludeWebkitKey = 'lineHeight' | 'something you need.'
type WebkitKey<K extends string, E = ExcludeWebkitKey> = K extends E ? never : `webkit${Capitalize<K>}`
Copy the code
Ha ha, isn’t it also very interesting. Indeed, that’s how interesting it is.
So let’s look at example 3. How can we get the type returned by data from methods? I have copied the example from the official website for you to have a look.
The difference between our example and the official website is that the official website is an object and we are a function, so we just change D to () => D.
So this time to share here, I will try to summarize more skills to share with you later.