国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

TypeScript在React中使用總結

lixiang / 2501人閱讀

摘要:事件處理我們在進行事件注冊時經常會在事件處理函數中使用事件對象,例如當使用鼠標事件時我們通過去獲取指針的坐標。接收,其代表事件處理函數中對象的類型。小王沒有內置從對象中排除是的屬性。

TypeScript 是 JS 類型的超集,并支持了泛型、類型、命名空間、枚舉等特性,彌補了 JS 在大型應用開發中的不足,那么當 TypeScript 與 React 一起使用會碰撞出怎樣的火花呢?接下來讓我們一起探索在 TypeScript2.8+ 版本中編寫 React 組件的姿勢。
前言

近幾年前端對 TypeScript 的呼聲越來越高,Ryan Dahl 的新項目 Deno 中 TypeScript 也變成了一個必須要會的技能,知乎上經常見到像『自從用了 TypeScript 之后,再也不想用 JavaScript 了』、『只要你用過 ES6,TypeScript 可以幾乎無門檻接入』、『TypeScript可以在任何場景代替 JS』這些類似的回答,抱著聽別人說不如自己用的心態逐漸嘗試在團隊內的一些底層支持的項目中使用 TypeScript。

使用 TypeScript 的編程體驗真的是爽到爆,當在鍵盤上敲下 . 時,后面這一大串的提示真的是滿屏幕的幸福,代碼質量和效率提升十分明顯,再也不想用 JavaScript 了。

在多帶帶使用 TypeScript 時沒有太大的坑,但是和一些框架結合使用的話坑還是比較多的,例如使用 React、Vue 這些框架的時候與 TypeScript 的結合會成為一大障礙,需要去查看框架提供的 .d.ts 的聲明文件中一些復雜類型的定義。本文主要聊一聊與 React 結合時經常遇到的一些類型定義問題,閱讀本文建議對 TypeScript 有一定了解,因為文中對于一些 TypeScript 的基礎的知識不會有太過于詳細的講解。

編寫第一個 TSX 組件
import React from "react"

import ReactDOM from "react-dom"



const App = () => {

 return (

  
Hello world
) } ReactDOM.render(, document.getElementById("root")

上述代碼運行時會出現以下錯誤

Cannot find module "react"

Cannot find module "react-dom"

錯誤原因是由于 ReactReact-dom 并不是使用 TS 進行開發的,所以 TS 不知道 ReactReact-dom 的類型,以及該模塊導出了什么,此時需要引入 .d.ts 的聲明文件,比較幸運的是在社區中已經發布了這些常用模塊的聲明文件 DefinitelyTyped 。

安裝 ReactReact-dom 類型定義文件
使用 yarn 安裝
yarn add @types/react

yarn add @types/react-dom
使用 npm 安裝
npm i @types/react -s

npm i @types/react-dom -s
有狀態組件開發

我們定義一個 App 有狀態組件,propsstate 如下。

Props
props 類型 是否必傳
color string
size string
State
props 類型
count string

使用 TSX 我們可以這樣寫

import * as React from "react";
interface IProps {
  color: string,
  size?: string,
}
interface IState {
  count: number,
}
class App extends React.Component {
  public state = {
    count: 1,
  }
  public render () {
    return (
      
Hello world
) } }

TypeScript 可以對 JSX 進行解析,充分利用其本身的靜態檢查功能,使用泛型進行 PropsState 的類型定義。定義后在使用 this.statethis.props 時可以在編輯器中獲得更好的智能提示,并且會對類型進行檢查。

那么 Component 的泛型是如何實現的呢,我們可以參考下 React 的類型定義文件 node_modules/@types/react/index.d.ts

在這里可以看到 Component 這個泛型類, P 代表 Props 的類型, S 代表 State 的類型。

class Component {

    readonly props: Readonly<{ children?: ReactNode }> & Readonly

; state: Readonly; }

Component 泛型類在接收到 PS 這兩個泛型變量后,將只讀屬性 props 的類型聲明為交叉類型 Readonly<{ children?: ReactNode }> & Readonly

; 使其支持 children 以及我們聲明的 colorsize

通過泛型的類型別名 Readonlyprops 的所有屬性都設置為只讀屬性。

Readonly 實現源碼 node_modules/typescript/lib/lib.es5.d.ts

由于 props 屬性被設置為只讀,所以通過 this.props.size = "sm" 進行更新時候 TS 檢查器會進行錯誤提示,Error:(23, 16) TS2540: Cannot assign to "size" because it is a constant or a read-only property

防止直接更新 state

React的 state 更新需要使用 setState 方法,但是我們經常誤操作,直接對 state 的屬性進行更新。

this.state.count = 2

開發中有時候會不小心就會寫出上面這種代碼,執行后 state 并沒有更新,我們此時會特別抓狂,心里想著我哪里又錯了?

現在有了 TypeScript 我們可以通過將 state ,以及 state 下面的屬性都設置為只讀類型,從而防止直接更新 state

import * as React from "react"
interface IProps {
  color: string,
  size?: string,
}
interface IState {
  count: number,
}
class App extends React.PureComponent {
  public readonly state: Readonly = {
    count: 1,
  }
  public render () {
    return (
      
Hello world
) } public componentDidMount () { this.state.count = 2 } } export default App

此時我們直接修改 state 值的時候 TypeScript 會立刻告訴我們錯誤,Error:(23, 16) TS2540: Cannot assign to "count" because it is a constant or a read-only property.

無狀態組件開發
Props
props 類型 是否必傳
children ReactNode
onClick function
SFC類型

在 React 的聲明文件中 已經定義了一個 SFC 類型,使用這個類型可以避免我們重復定義 childrenpropTypescontextTypesdefaultPropsdisplayName 的類型。

實現源碼 node_modules/@types/react/index.d.ts

type SFC

= StatelessComponent

; interface StatelessComponent

{ (props: P & { children?: ReactNode }, context?: any): ReactElement | null; propTypes?: ValidationMap

; contextTypes?: ValidationMap; defaultProps?: Partial

; displayName?: string; }

使用 SFC 進行無狀態組件開發。

import { SFC } from "react"
import { MouseEvent } from "react"
import * as React from "react"
interface IProps {
  onClick (event: MouseEvent): void,
}
const Button: SFC = ({onClick, children}) => {
  return (
    
{ children }
) } export default Button
事件處理

我們在進行事件注冊時經常會在事件處理函數中使用 event 事件對象,例如當使用鼠標事件時我們通過 clientXclientY 去獲取指針的坐標。

大家可以想到直接把 event 設置為 any 類型,但是這樣就失去了我們對代碼進行靜態檢查的意義。

function handleEvent (event: any) {
  console.log(event.clientY)
}

試想下當我們注冊一個 Touch 事件,然后錯誤的通過事件處理函數中的 event 對象去獲取其 clientY 屬性的值,在這里我們已經將 event 設置為 any 類型,導致 TypeScript 在編譯時并不會提示我們錯誤, 當我們通過 event.clientY 訪問時就有問題了,因為 Touch 事件的 event 對象并沒有 clientY 這個屬性。

通過 interfaceevent 對象進行類型聲明編寫的話又十分浪費時間,幸運的是 React 的聲明文件提供了 Event 對象的類型聲明。

Event 事件對象類型

常用 Event 事件對象類型:

ClipboardEvent 剪貼板事件對象

DragEvent 拖拽事件對象

ChangeEvent Change 事件對象

KeyboardEvent 鍵盤事件對象

MouseEvent 鼠標事件對象

TouchEvent 觸摸事件對象

WheelEvent 滾輪事件對象

AnimationEvent 動畫事件對象

TransitionEvent 過渡事件對象

實例:

import { MouseEvent } from "react"

interface IProps {

  onClick (event: MouseEvent): void,
}

MouseEvent 類型實現源碼 node_modules/@types/react/index.d.ts

interface SyntheticEvent {
        bubbles: boolean;
        /**
         * A reference to the element on which the event listener is registered.
         */
        currentTarget: EventTarget & T;
        cancelable: boolean;
        defaultPrevented: boolean;
        eventPhase: number;
        isTrusted: boolean;
        nativeEvent: Event;
        preventDefault(): void;
        isDefaultPrevented(): boolean;
        stopPropagation(): void;
        isPropagationStopped(): boolean;
        persist(): void;
        // If you thought this should be `EventTarget & T`, see https://github.com/DefinitelyTyped/DefinitelyTyped/pull/12239
        /**
         * A reference to the element from which the event was originally dispatched.
         * This might be a child element to the element on which the event listener is registered.
         *
         * @see currentTarget
         */
        target: EventTarget;
        timeStamp: number;
        type: string;
}



interface MouseEvent extends SyntheticEvent {
        altKey: boolean;
        button: number;
        buttons: number;
        clientX: number;
        clientY: number;
        ctrlKey: boolean;
        /**
         * See [DOM Level 3 Events spec](https://www.w3.org/TR/uievents-key/#keys-modifier). for a list of valid (case-sensitive) arguments to this method.
         */
        getModifierState(key: string): boolean;
        metaKey: boolean;
        nativeEvent: NativeMouseEvent;
        pageX: number;
        pageY: number;
        relatedTarget: EventTarget;
        screenX: number;
        screenY: number;
        shiftKey: boolean;
    }

EventTarget 類型實現源碼 node_modules/typescript/lib/lib.dom.d.ts

interface EventTarget {
    addEventListener(type: string, listener: EventListenerOrEventListenerObject | null, options?: boolean | AddEventListenerOptions): void;
    dispatchEvent(evt: Event): boolean;
    removeEventListener(type: string, listener?: EventListenerOrEventListenerObject | null, options?: EventListenerOptions | boolean): void;
}

通過源碼我們可以看到 MouseEvent 繼承 SyntheticEvent,并且通過 T 接收一個 DOM 元素的類型, currentTarget 的類型由 EventTarget & T 組成交叉類型。

事件處理函數類型

當我們定義事件處理函數時有沒有更方便定義其函數類型的方式呢?答案是使用 React 聲明文件所提供的 EventHandler 類型別名,通過不同事件的 EventHandler 的類型別名來定義事件處理函數的類型。

EventHandler 類型實現源碼 node_modules/@types/react/index.d.ts

    type EventHandler> = { bivarianceHack(event: E): void }["bivarianceHack"];
    type ReactEventHandler = EventHandler>;
    type ClipboardEventHandler = EventHandler>;
    type DragEventHandler = EventHandler>;
    type FocusEventHandler = EventHandler>;
    type FormEventHandler = EventHandler>;
    type ChangeEventHandler = EventHandler>;
    type KeyboardEventHandler = EventHandler>;
    type MouseEventHandler = EventHandler>;
    type TouchEventHandler = EventHandler>;
    type PointerEventHandler = EventHandler>;
    type UIEventHandler = EventHandler>;
    type WheelEventHandler = EventHandler>;
    type AnimationEventHandler = EventHandler>;
    type TransitionEventHandler = EventHandler>;

EventHandler 接收 E ,其代表事件處理函數中 event 對象的類型。

bivarianceHack 為事件處理函數的類型定義,函數接收一個 event 對象,并且其類型為接收到的泛型變量 E 的類型, 返回值為 void

實例:

interface IProps {
  onClick : MouseEventHandler,
}
Promise 類型

在做異步操作時我們經常使用 async 函數,函數調用時會 return 一個 Promise 對象,可以使用 then 方法添加回調函數。

Promise 是一個泛型類型,T 泛型變量用于確定使用 then 方法時接收的第一個回調函數(onfulfilled)的參數類型。

實例:

interface IResponse {
  message: string,
  result: T,
  success: boolean,
}
async function getResult (): Promise> {
  return {
    message: "獲取成功",
    result: [1, 2, 3],
    success: true,
  }
}
getResult()
  .then(result => {
    console.log(result.result)
  })

我們首先聲明 IResponse 的泛型接口用于定義 response 的類型,通過 T 泛型變量來確定 result 的類型。

然后聲明了一個 異步函數 getResult 并且將函數返回值的類型定義為 Promise>

最后調用 getResult 方法會返回一個 promise 類型,通過 .then 調用,此時 .then 方法接收的第一個回調函數的參數 result 的類型為,{ message: string, result: number[], success: boolean}

Promise 實現源碼 node_modules/typescript/lib/lib.es5.d.ts

interface Promise {
    /**
     * Attaches callbacks for the resolution and/or rejection of the Promise.
     * @param onfulfilled The callback to execute when the Promise is resolved.
     * @param onrejected The callback to execute when the Promise is rejected.
     * @returns A Promise for the completion of which ever callback is executed.
     */
    then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise;
    /**
     * Attaches a callback for only the rejection of the Promise.
     * @param onrejected The callback to execute when the Promise is rejected.
     * @returns A Promise for the completion of the callback.
     */
    catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise;
}
工具泛型使用技巧
typeof

一般我們都是先定義類型,再去賦值使用,但是使用 typeof 我們可以把使用順序倒過來。

const options = {
  a: 1
}
type Options = typeof options
使用字符串字面量類型限制值為固定的字符串參數

限制 props.color 的值只可以是字符串 redblueyellow

interface IProps {
  color: "red" | "blue" | "yellow",
}
使用數字字面量類型限制值為固定的數值參數

限制 props.index 的值只可以是數字 012

interface IProps {
 index: 0 | 1 | 2,
}
使用 Partial 將所有的 props 屬性都變為可選值

Partial 實現源碼 node_modules/typescript/lib/lib.dom.d.ts

type Partial = { [P in keyof T]?: T[P] };

上面代碼的意思是 keyof T 拿到 T 所有屬性名, 然后 in 進行遍歷, 將值賦給 P , 最后 T[P] 取得相應屬性的值,中間的 ? 用來進行設置為可選值。

如果 props 所有的屬性值都是可選的我們可以借助 Partial 這樣實現。

import { MouseEvent } from "react"
import * as React from "react"
interface IProps {
  color: "red" | "blue" | "yellow",
  onClick (event: MouseEvent): void,
}
const Button: SFC> = ({onClick, children, color}) => {
  return (
    
{ children }
)
使用 Required 將所有 props 屬性都設為必填項

Required 實現源碼 node_modules/typescript/lib/lib.dom.d.ts

type Required = { [P in keyof T]-?: T[P] };

看到這里,小伙伴們可能有些疑惑, -? 是做什么的,其實 -? 的功能就是把 ? 去掉變成可選項,對應的還有 +? ,作用與 -? 相反,是把屬性變為可選項。

條件類型

TypeScript2.8引入了條件類型,條件類型可以根據其他類型的特性做出類型的判斷。

T extends U ? X : Y

原先

interface Id { id: number, /* other fields */ }
interface Name { name: string, /* other fields */ }
declare function createLabel(id: number): Id;
declare function createLabel(name: string): Name;
declare function createLabel(name: string | number): Id | Name;

使用條件類型

type IdOrName = T extends number ? Id : Name;
declare function createLabel(idOrName: T): T extends number ? Id : Name;
Exclude

T 中排除那些可以賦值給 U 的類型。

Exclude 實現源碼 node_modules/typescript/lib/lib.es5.d.ts

type Exclude = T extends U ? never : T;

實例:

type T = Exclude<1|2|3|4|5, 3|4>  // T = 1|2|5 

此時 T 類型的值只可以為 125 ,當使用其他值是 TS 會進行錯誤提示。

Error:(8, 5) TS2322: Type "3" is not assignable to type "1 | 2 | 5".

Extract

T 中提取那些可以賦值給 U 的類型。

Extract實現源碼 node_modules/typescript/lib/lib.es5.d.ts

type Extract = T extends U ? T : never;

實例:

type T = Exclude<1|2|3|4|5, 3|4>  // T = 3|4

此時T類型的值只可以為 34 ,當使用其他值時 TS 會進行錯誤提示:

Error:(8, 5) TS2322: Type "5" is not assignable to type "3 | 4".

Pick

T 中取出一系列 K 的屬性。

Pick 實現源碼 node_modules/typescript/lib/lib.es5.d.ts

type Pick = {
    [P in K]: T[P];
};

實例:

假如我們現在有一個類型其擁有 nameagesex 屬性,當我們想生成一個新的類型只支持 nameage 時可以像下面這樣:

interface Person {
  name: string,
  age: number,
  sex: string,
}
let person: Pick = {
  name: "小王",
  age: 21,
}
Record

K 中所有的屬性的值轉化為 T 類型。

Record 實現源碼 node_modules/typescript/lib/lib.es5.d.ts

type Record = {
    [P in K]: T;
};

實例:

nameage 屬性全部設為 string 類型。

let person: Record<"name" | "age", string> = {
  name: "小王",
  age: "12",
}
Omit(沒有內置)

從對象 T 中排除 key K 的屬性。

由于 TS 中沒有內置,所以需要我們使用 PickExclude 進行實現。

type Omit = Pick>

實例:

排除 name 屬性。

interface Person {
  name: string,
  age: number,
  sex: string,
}


let person: Omit = {
  age: 1,
  sex: "男"
}
NonNullable

排除 Tnullundefined

NonNullable 實現源碼 node_modules/typescript/lib/lib.es5.d.ts

type NonNullable = T extends null | undefined ? never : T;

實例:

type T = NonNullable; // string | string[]
ReturnType

獲取函數 T 返回值的類型。。

ReturnType 實現源碼 node_modules/typescript/lib/lib.es5.d.ts

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

infer R 相當于聲明一個變量,接收傳入函數的返回值類型。

實例:

type T1 = ReturnType<() => string>; // string
type T2 = ReturnType<(s: string) => void>; // void

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/98008.html

相關文章

  • React項目從Javascript到Typescript的遷移經驗總結

    摘要:面對越來越火的,我們公司今年也逐漸開始擁抱。綜上所述,我個人覺得是要刪除相關的東西,降低項目復雜度。但是有一個例外情況。這個配置項有三個值可選擇,分別是和。模式會生成,在使用前不需要再進行轉換操作了,輸出文件的擴展名為。 拋轉引用 現在越來越多的項目放棄了javascript,而選擇擁抱了typescript,就比如我們熟知的ant-design就是其中之一。面對越來越火的typesc...

    zhisheng 評論0 收藏0
  • 兩年React老兵的總結 - 類型檢查篇

    摘要:系列引言最近準備培訓新人為了方便新人較快入手開發并編寫高質量的組件代碼我根據自己的實踐經驗對組件設計的相關實踐和規范整理了一些文檔將部分章節分享了出來由于經驗有限文章可能會有某些錯誤希望大家指出互相交流由于篇幅太長所以拆分為幾篇文章主要有以 系列引言 最近準備培訓新人, 為了方便新人較快入手 React 開發并編寫高質量的組件代碼, 我根據自己的實踐經驗對React 組件設計的相關實踐...

    scola666 評論0 收藏0
  • 「每日一瞥

    摘要:即使中沒有錯誤,仍然會執行,這一點一般都是知道的。我們認為這是正確的前進道路,兼具戰略性和務實性降低使用門檻開發人員遷移到的障礙之一是從到的并不輕松的遷移。下一步將通過一系列功能和插件為的平滑過渡提供支持,并以此回饋社區。 showImg(https://segmentfault.com/img/remote/1460000017516912?w=1200&h=630); useSt...

    XboxYan 評論0 收藏0
  • React+TypeScript+Mobx+AntDesignMobile進行移動端項目搭建

    摘要:通過裝飾器或者利用時調用的函數來進行使用下面代碼中當或者發生變化時,會監聽數據變化確保通過觸發方法自動更新。只能影響正在運行的函數,而無法影響當前函數調用的異步操作參考官方文檔用法裝飾器函數遵循中標準的綁定規則。 前言: 本文基于React+TypeScript+Mobx+AntDesignMobile技術棧,使用Create-React-App腳手架進行一個移動端項目搭建,主要介紹項...

    lindroid 評論0 收藏0
  • TypeScript極速完全入門-3ts結合react進行項目開發

    摘要:前面我們已經說了大部分的核心內容,接下來我們就說說如何用開發實際項目。因為和結合很緊密,資料也很多,而且我會找機會專門說下這方面的知識,所以我們將重點放到如何用結合上來。所以前面打牢基礎,現在我們開始實際組建工作流。 前面我們已經說了大部分typescript的核心內容,接下來我們就說說如何用typescript開發實際項目。 因為angular和typescript結合很緊密,資料也...

    arashicage 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<