天天看點

無比打字與拼英打字_了解打字稿的怪異部分 了解打字稿的怪異部分 (Understanding the Weird Parts of Typescript) 泛型<T> (Generics <T>) 注意事項 (NOTE TO MENTION) 下一部分—實用程式類型 (Next part — Utility Types) 最後一個主題-事件處理程式 (Last subject — Event handlers) 最後的話 (Last words)

無比打字與拼英打字

了解打字稿的怪異部分 (Understanding the Weird Parts of Typescript)

Typescript, in spite of all its advantages, can be hard to swallow at first.

盡管打字稿有很多優點,但一開始可能很難被吞下。

Readability of Typescript code, is the main reason in my opinion, for developers being reluctant to give it a real shot.

我認為打字稿代碼的可讀性是主要原因,因為開發人員不願對其進行實際拍攝。

Let’s take a look at this piece of code:

讓我們看一下這段代碼:

I think you would agree with me that if all TS code looked like that, there were no readability issues. Javascript developers would not have to go through any kind of tutorial, because this code is self-explanatory. Considering that, the transition to TS would have become much easier.

我想您會同意我的看法,即如果所有TS代碼都看起來像那樣,那麼就不會出現可讀性問題。 Javascript開發人員不必經曆任何類型的教程,因為該代碼是不言自明的。 考慮到這一點,向TS的過渡将變得更加容易。

Now, what about this?

現在,那呢?

This code is less pleasant, to say the least. It gives us reusable types to work with. I extracted it from one of the projects I have been working on, but such code is a common thing to find in other projects as well.

至少可以說,這段代碼不太愉快。 它為我們提供了可重用的類型。 我從一個我一直在從事的項目中提取了它,但是在其他項目中也經常找到這樣的代碼。

The purpose of this post is to give you the tools, to be able to read and write such code yourself. We will do it using real-life examples from the front-end world, of building highly reusable components using Typescript with React.

這篇文章的目的是為您提供工具,使您能夠自己讀取和編寫此類代碼。 我們将使用來自前端世界的真實示例來完成此任務,即使用帶有React的Typescript建構高度可重用的元件。

We will explore 3 subjects — Generics, Utility types, and Event handlers.

我們将探讨3個主題-泛型,實用程式類型和事件處理程式。

泛型<T> (Generics <T>)

Let’s take a look at the following example — A reusable table component.

讓我們看下面的示例—一個可重用的表元件。

無比打字與拼英打字_了解打字稿的怪異部分 了解打字稿的怪異部分 (Understanding the Weird Parts of Typescript) 泛型&lt;T&gt; (Generics &lt;T&gt;) 注意事項 (NOTE TO MENTION) 下一部分—實用程式類型 (Next part — Utility Types) 最後一個主題-事件處理程式 (Last subject — Event handlers) 最後的話 (Last words)
  1. Our table component can be set with any kind of data for the columns and rows.

    我們的表格元件可以設定任何類型的列和行資料。

  2. The data in the table can be sorted by clicking on the column’s title.

    通過單擊列标題可以對表中的資料進行排序。

  3. A single row can be selected when the user clicks on it.

    使用者單擊時可以選擇單個行。

In order to achieve this behavior we will use this simple code:

為了實作此行為,我們将使用以下簡單代碼:

Now, a developer who wishes to use our reusable component to display a list of candidates will use it this way:

現在,希望使用我們的可重用元件顯示候選人清單的開發人員将以這種方式使用它:

Code looks good, but what about type safety? In order to achieve it, we will rewrite this code with Typescript and use Generics.

代碼看起來不錯,但是類型安全呢? 為了實作它,我們将使用Typescript重寫此代碼并使用泛型。

The interesting parts of this code are lines 6, 7, and 20.

該代碼有趣的部分是第6、7和20行 。

Line 7 is the easy one, we are telling Typescript that the Array is of type

Candidate

. Since Array is a generic type, we are using this syntax:

Array<Candidate>

.

第7行很簡單,我們告訴Typescript Array是

Candidate

類型。 由于Array是通用類型,是以我們使用以下文法:

Array<Candidate>

Line 20 — We need

Table

to know what type of rows it contains, so we pass it the

Candidate

type -

Table<Candidate>

. In the next code snippet, you will see how

Table

is using this new

<>

keyword.

第20行-我們需要

Table

知道其包含的行類型,是以我們将其傳遞給

Candidate

類型-

Table<Candidate>

。 在下一個代碼段中,您将看到

Table

如何使用這個新的

<>

關鍵字。

Line 6 — That one is indeed weird. What we try to achieve here, is to verify the items of columns array, can only be the keys of the row type — Candidate. For example, if we make a mistake and instead of passing

firstName

we pass

firsName

, Typescript will alert us:

第6行 -那确實很奇怪。 我們在這裡試圖實作的是驗證columns數組的項目,它隻能是行類型的鍵-Candidate。 例如,如果我們犯了一個錯誤,而不是傳遞

firstName

我們通過

firsName

, Typescript會提醒我們:

So when are we actually using these types and benefit from them?

那麼我們何時真正使用這些類型并從中受益呢?

Take a look at our callback functions:

看一下我們的回調函數:

In order to access firstName, lastName, and age, in the function's signatures, we declared

row: Candidate

.

為了通路函數簽名中的firstName,lastName和age,我們聲明了

row: Candidate

We later on pass these functions to our component:

稍後我們将這些功能傳遞給我們的元件:

If we try to pass an invalid signature, for example, a

Product

instead of a

Candidate

, then Typescript will alert us:

如果我們嘗試傳遞無效的簽名,例如

Product

而不是

Candidate

,那麼Typescript将警告我們:

Ok, so we modified our Table’s usage code, now let’s see how we rewrite the

Table

to work with it:

好的,是以我們修改了Table的用法代碼,現在讓我們看看如何重寫

Table

來使用它:

As our Table component provides the following props:

rows, cols, onRowClick, and onSortClick

, we created an interface for them.

由于我們的Table元件提供以下道具:

rows, cols, onRowClick, and onSortClick

,我們為它們建立了一個接口。

This interface can get whatever

RowDataType

we want. It could be a Candidate, a Product, etc’.

該接口可以擷取我們想要的任何

RowDataType

。 它可以是候選人,産品等。

Well, I lied a bit, not whatever we want, but at least one that contains an

id:string

so we can manage it better internally in our Table component.

好吧,我撒謊了,不是我們想要的,而是至少包含了一個

id:string

以便我們可以在Table元件内部更好地對其進行管理。

This

extends

syntax enforces it:

extends

文法以強制執行:

The generic interface saves us from repeating ourselves again and again for each different type:

通用接口使我們不必為每種不同的類型重複一次:

Going back to the rest of Table’s code:

回到表的其餘代碼:

Line 1 —

Table<RowDataType>

enables us to use

RowDataType

anywhere we want through the function. You can do the same exercise we did before, remove the generic on top, and replace all its instances in the function’s body with

Candidate

.

第1行

Table<RowDataType>

使我們能夠通過函數在任何需要的地方使用

RowDataType

。 您可以執行與之前相同的操作,在頂部删除泛型,并将其在函數體内的所有執行個體替換為

Candidate

注意事項 (NOTE TO MENTION)

In most code, you will encounter a short version of naming like T, K, V, etc’.

在大多數代碼中,您會遇到諸如T,K,V等的簡短命名。

I choose to write the full meaningful name -

<RowDataType>

for better clarity of the examples. But could of-course do it the shorter way:

為了更好地說明示例,我選擇寫完整的有意義的名稱-

<RowDataType>

。 當然可以用更短的方法做到這一點:

下一部分—實用程式類型 (Next part — Utility Types)

This part talks about

Partial, Pick, and Omit

which are part of the utility types that Typescript supply. These types help us make types’ transformations. The official typescript docs contain a short and solid doc about it.

本部分讨論TypeScript提供的實用程式類型的一部分

Partial, Pick, and Omit

。 這些類型幫助我們進行類型的轉換。 官方打字稿文檔包含簡短而可靠的文檔 。

What we will do here, is give real-life examples of such usages.

我們将在此處提供此類用法的真實示例。

Modal example:

模态示例:

Let’s say that you want to create a reusable Modal component, to be used across your different applications.

假設您要建立一個可重用的Modal元件,以便在您的不同應用程式中使用。

Consider your Modal is based on react-modal to save you the time of handling the gray-out area, z-index layers, accessibility, and more.

考慮您的模态基于react-modal,可以節省處理灰區,z-index圖層,可通路性等的時間。

Because we want all our apps to feel the same, our Modal will have a strict design — black border, white background, and dynamic width and height.

因為我們希望所有應用程式都具有相同的感覺,是以Modal的設計必須嚴格-黑色邊框,白色背景以及動态寬度和高度。

In order to achieve it, we will allow our user to pass all react-modal props, besides the ones related to design.

為了實作這一目标,我們将允許使用者通過除 設計相關的所有React式道具。

Our code would like somewhat like this (longer and more precise working example can be found at the end of this post):

我們的代碼有點像這樣(在本文的結尾可以找到更長時間和更精确的工作示例):

Line4 — all the props that we wish to Omit

Line4-我們希望省略的所有道具

Line5 — creates a new type — all react-modal props, except for the design ones.

第5行 -建立一種新類型-除了設計的以外,所有其他React式道具。

Line6 — creates a new type — the reduced react-modal props + width and height props.

第6行-建立一種新類型-簡化後的React模式道具+寬度和高度道具。

Line17 — notice how we are using the ES6 rest parameter syntax to forward the rest of the props to react-modal. Thanks to

Omit

, we can be sure our user won’t pass unwanted design props like

className

for example.

Line17 —注意我們如何使用ES6 rest參數文法将其餘的props轉發到react-modal。 感謝

Omit

,我們可以確定我們的使用者不會傳遞不需要的設計道具,例如

className

We have seen a real-life example of

Omit

usage. What about

Pick

?

我們已經看到了

Omit

用法的真實示例。 那

Pick

呢?

Pick

is doing the opposite, it gives us back only the props that we wish to keep. So if we would like to get only a small portion of the props, it would make more sense to use Pick:

Pick

在做相反的,它給了我們回到隻有我們希望保持道具。 是以,如果我們隻想獲得一小部分道具,那麼使用Pick會更有意義:

Lines 1–3: Demonstrates a one-liner for the types which is more common. If it’s not clear at first read, I suggest you split it into multiple lines like in the previous example.

第1至3行:為更常見的類型展示單線。 如果一開始不清楚,建議您像前面的示例一樣将其分成多行。

With this type, the consumer of this component will be able to pass only 4 props — isOpen, style, width, and height.

使用此類型時,此元件的使用者将隻能傳遞4個道具-isOpen,style,width和height。

Another useful utility type is

Partial

, which takes a type and make all its props optional.

另一個有用的實用程式類型是

Partial

,它接受一個類型并将其所有道具設為可選。

In react-modal props, only

isOpen

is mandatory. If we decide that in our modal it is not mandatory but uses a default value when not supplied, we can still reuse react-modal types using

Partial

:

在react-modal道具中,僅

isOpen

是必需的。 如果我們确定模态不是強制性的,而是在未提供模态時使用預設值,則仍可以使用

Partial

重用react-modal類型:

This is almost the same code as in the first modal example, but notice how we use

Partial

in line5 and give a default value

isOpen=false

in line9.

這幾乎是相同的代碼作為第一模式的例子,但注意我們是如何使用

Partial

在LINE5并給予了預設值

isOpen=false

在line9。

最後一個主題-事件處理程式 (Last subject — Event handlers)

Another piece of code that looks weird at first is where we use existing types for event handlers.

一開始看起來很奇怪的另一段代碼是我們将現有類型用于事件處理程式。

Let’s take a look at this auto-complete example:

讓我們看一下這個自動完成的例子:

As you can see from the interface, our component expects to get a

className

for design purposes,

options

to display for the auto-completion, the selected

value

and in lines 5–11 callback functions to execute as event handlers.

從界面可以看到,我們的元件希望獲得一個

className

用于設計目的,為自動完成顯示的

options

,所選

value

以及在第5-11行中用作事件處理程式的回調函數。

A developer would use our component somewhat like this:

開發人員會使用我們的元件,如下所示:

Lines 3–4 —

handleOnChange

is setting the state with the selected value, which is

e.target.value

.

第3至4行

handleOnChange

使用標明的值

e.target.value

設定狀态。

In order to work safely with

e

we had to know it’s type and that is what this

React.ChangeEventHandler<HTMLInputElement>

gives us.

為了安全地使用

e

我們必須知道它的類型,這就是

React.ChangeEventHandler<HTMLInputElement>

給我們的。

If we had to write this type ourselves, we would use HTMLInputElement type and augment it with

target.

It is not a fun task, and luckily React does it for us, for all kind of event handlers.

如果必須自己編寫此類型,則可以使用HTMLInputElement類型,并使用

target.

對其進行擴充

target.

這不是一個有趣的任務,幸運的是,React為我們完成了所有類型的事件處理程式。

So, getting familiar with this useful types for event handlers is important. If you like to improve your Typescript skills even better, take a look here at how React implements it.

是以,熟悉用于事件處理程式的有用類型非常重要。 如果您想更好地提高Typescript技能,請在此處檢視 React如何實作它。

最後的話 (Last words)

The code examples in the post were reduced for better clarity of the idea I tried to convey. Longer and more precise versions of all code examples can be found here.

為了簡化我試圖傳達的想法,減少了文章中的代碼示例。 在這裡可以找到所有代碼示例的更長,更精确的版本。

I really hope you enjoyed reading this post, and gained a thing or two from it, at least I did.

我真的希望您喜歡閱讀這篇文章,并從中獲得了一兩個東西,至少我是這樣做的。

Feel free to leave a comment below with any questions or feedback you might have.

如果您有任何疑問或回報,請随時在下面發表評論。

翻譯自: https://medium.com/swlh/understanding-the-weird-parts-of-typescript-20c0fe26d314

無比打字與拼英打字