Autosave: 2023-04-05 20:34:06
This commit is contained in:
parent
0189c561e2
commit
b40968eefc
2 changed files with 116 additions and 0 deletions
|
|
@ -4,3 +4,117 @@ categories:
|
||||||
tags:
|
tags:
|
||||||
- typescript
|
- typescript
|
||||||
---
|
---
|
||||||
|
|
||||||
|
# Further examples of generics in TypeScript
|
||||||
|
|
||||||
|
## Basic function
|
||||||
|
In the code below we have a simple JavaScript function that receives a value and an an array as parameters. It returns a new array comprising the original array plus the additional value:
|
||||||
|
|
||||||
|
```js
|
||||||
|
function generateArray(existingArray, newValue) {
|
||||||
|
return [...existingArray, newValue];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Imagine that we want to ensure that each of the parameters share the same data type. In other words: if the function is passed a string array, the second parameter must also be a string. For example, it should not be the case that you can append a string to an array of numbers.
|
||||||
|
|
||||||
|
Now imagine that we don't know in advance what type the value or array will be, we just know that the data types of the parameters must match.
|
||||||
|
|
||||||
|
In converting the function to TypeScript, one way of overcoming our lack of foreknowledge would be to deploy `any`. This way it doesn't matter which types are passed to the function:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
function generateArray(existingArray: any[], newValue: any): any[] {
|
||||||
|
return [...existingArray, newValue];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
But this is no solution at all. The problem — as always with `any` — is that it strips our function of any type checks whatsoever and would therefore invite calls of form: `generateArray([1,2,3], 'lorem')`.
|
||||||
|
|
||||||
|
Enter generics:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
function generateArray<T>(existingArr: T[], newValue: T): T[] {
|
||||||
|
return [...existingArr, newValue];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Now, whilst we haven't asserted ahead of time which types will be used, whichever types we do pass in, must match. The function header is saying:
|
||||||
|
|
||||||
|
- both arguments must be of the same type (represented by `T`)
|
||||||
|
- the function will return an array of this same `T` type.
|
||||||
|
|
||||||
|
If I then tried to run the function with unmatched types (for example `generateArray([1,2,3,4], true)` ) TypeScript would raise the following error:
|
||||||
|
|
||||||
|
```
|
||||||
|
Argument of type 'boolean' is not assignable to parameter of type 'number'
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that even though the function in question does not express any preference for number types, given that our first parameter is a number, TypeScript knows that the second parameter must also be a number.
|
||||||
|
|
||||||
|
> In the generic function we have used `T` as our placeholder for a generic type as this is the convention. However there is no compunction to do so. We could have used any letter or string, providing that the string is not a reserved term.
|
||||||
|
|
||||||
|
### More advanced function
|
||||||
|
|
||||||
|
This example demonstrates how we can use generics to reduce repetition when writing functions and is also a more realistic use case.
|
||||||
|
|
||||||
|
Let's say we have two types or interfaces:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
type VideoFormatUrls = {
|
||||||
|
format720p: URL;
|
||||||
|
format1080p: URL;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
type SubtitleFormatUrls = {
|
||||||
|
english: URL;
|
||||||
|
german: URL;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
An example of an object matching these type definitions:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
const videoFormats: VideoFormatUrls = {
|
||||||
|
format720p: https://www.format720p.co.uk,
|
||||||
|
format1080p: https://www.format1080p.co.uk
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Imagine we wanted to be able to check whether a given film is available in a certain video format. We could write a function like this:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
function isFormatAvailable(obj: VideoFormatUrls, format: string): format is keyof VideoFormatUrls {
|
||||||
|
return format in obj;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Now imagine that we need to do the same thing with subtitles, but given that `isFormatAvailable()` is typed to the `VideoFormatUrls` type we would get an error if we used this function for subtitles. But we also don't want to write a near identical function typed to `SubtitleFormatUrls` to subtitles just to ensure adequate type safety.
|
||||||
|
|
||||||
|
Alternatively we could use a union type, for example:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
function isFormatAvailable(
|
||||||
|
obj: VideoFormatUrls | SubtitleFormatUrls,
|
||||||
|
format: string,
|
||||||
|
): format is keyof VideoFormatUrls {
|
||||||
|
return format in obj;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
But this quickly becomes unwieldy if we, for the sake of argument have a great many URL types that we want the function to utilise.
|
||||||
|
|
||||||
|
This is where generics become super helpful. Here is how we would rewrite the function as a generic:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
function isAvailable<Formats>(obj: Formats, key: string): key is keyof Formats {
|
||||||
|
return key in obj;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
We could then explicitly type our calls of this function, viz:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
isFormatAvailable<SubtitleFormatUrls>(subtitles, 'english');
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,8 @@ J. Hunt. 2019. **An Advanced Guide to Python Programming**
|
||||||
|
|
||||||
[Learning Arduino with Python](https://realpython.com/arduino-python/)
|
[Learning Arduino with Python](https://realpython.com/arduino-python/)
|
||||||
|
|
||||||
|
[Python Programming Projects](https://github.com/zhiwehu/Python-programming-exercises/blob/master/100%2B%20Python%20challenging%20programming%20exercises.txt)
|
||||||
|
|
||||||
## Shell
|
## Shell
|
||||||
|
|
||||||
B. Perry, D. Taylor. 2015. **Wicked Cool Shell Scripts**
|
B. Perry, D. Taylor. 2015. **Wicked Cool Shell Scripts**
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue