中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁(yè) > news >正文

菏澤網(wǎng)站建設(shè) 梧桐樹(shù)域名查詢(xún)?cè)L問(wèn)

菏澤網(wǎng)站建設(shè) 梧桐樹(shù),域名查詢(xún)?cè)L問(wèn),網(wǎng)站建設(shè)新聞發(fā)布注意,垂直型b2c網(wǎng)站本文根據(jù)日常開(kāi)發(fā)實(shí)踐,參考優(yōu)秀文章、文檔,來(lái)說(shuō)說(shuō) TypeScript 是如何較優(yōu)雅的融入 React 項(xiàng)目的。 溫馨提示:日常開(kāi)發(fā)中已全面擁抱函數(shù)式組件和 React Hooks,class 類(lèi)組件的寫(xiě)法這里不提及。 前沿 以前有 JSX 語(yǔ)法,…

本文根據(jù)日常開(kāi)發(fā)實(shí)踐,參考優(yōu)秀文章、文檔,來(lái)說(shuō)說(shuō) TypeScript 是如何較優(yōu)雅的融入 React 項(xiàng)目的。

溫馨提示:日常開(kāi)發(fā)中已全面擁抱函數(shù)式組件和 React Hooksclass 類(lèi)組件的寫(xiě)法這里不提及。

前沿

  • 以前有 JSX 語(yǔ)法,必須引入 React。React 17.0+ 不需要強(qiáng)制聲明 React 了。
import React, { useState } from 'react';// 以后將被替代成
import { useState } from 'react';
import * as React from 'react';

基礎(chǔ)介紹

基本類(lèi)型

  • 基礎(chǔ)類(lèi)型就沒(méi)什么好說(shuō)的了,以下都是比較常用的,一般比較好理解,也沒(méi)什么問(wèn)題。
type BasicTypes = {message: string;count: number;disabled: boolean;names: string[]; // or Array<string>id: string | number; // 聯(lián)合類(lèi)型
}

聯(lián)合類(lèi)型

一般的聯(lián)合類(lèi)型,沒(méi)什么好說(shuō)的,這里提一下非常有用,但新手經(jīng)常遺忘的寫(xiě)法 —— 字符字面量聯(lián)合。

  • 例如:自定義 ajax 時(shí),一般 method 就那么具體的幾種:getpost、put 等。
    大家都知道需要傳入一個(gè) string 型,你可能會(huì)這么寫(xiě):
type UnionsTypes = {method: string; // ? bad,可以傳入任意字符串
};
  • 使用字符字面量聯(lián)合類(lèi)型,第一、可以智能提示你可傳入的字符常量;第二、防止拼寫(xiě)錯(cuò)誤。后面會(huì)有更多的例子。
type UnionsTypes = {method: 'get' | 'post'; // ? good 只允許 'get'、'post' 字面量
};

對(duì)象類(lèi)型

  • 一般你知道確切的屬性類(lèi)型,這沒(méi)什么好說(shuō)的。
type ObjectTypes = {obj3: {id: string;title: string;};objArr: {id: string;title: string;}[]; // 對(duì)象數(shù)組,or Array<{ id: string, title: string }>
};
  • 但有時(shí)你只知道是個(gè)對(duì)象,而不確定具體有哪些屬性時(shí),你可能會(huì)這么用:
type ObjectTypes = {obj: object; // ? bad,不推薦obj2: {}; // ? bad 幾乎類(lèi)似 object
};
  • 一般編譯器會(huì)提示你,不要這么使用,推薦使用 Record
type ObjectTypes = {objBetter: Record<string, unknown>; // ? better,代替 obj: object// 對(duì)于 obj2: {}; 有三種情況:obj2Better1: Record<string, unknown>; // ? better 同上obj2Better2: unknown; // ? any valueobj2Better3: Record<string, never>; // ? 空對(duì)象/** Record 更多用法 */dict1: {[key: string]: MyTypeHere;};dict2: Record<string, MyTypeHere>; // 等價(jià)于 dict1
};
  • Record 有什么好處呢,先看看實(shí)現(xiàn):
// 意思就是,泛型 K 的集合作為返回對(duì)象的屬性,且值類(lèi)型為 T
type Record<K extends keyof any, T> = {[P in K]: T;
};
  • 官方的一個(gè)例子
interface PageInfo {title: string;
}type Page = 'home' | 'about' | 'contact';const nav: Record<Page, PageInfo> = {about: { title: 'about' },contact: { title: 'contact' },// TS2322: Type '{ about: { title: string; }; contact: { title: string; }; hoem: { title: string; }; }' // is not assignable to type 'Record<Page, PageInfo>'. ...hoem: { title: 'home' },
};nav.about;

好處:

  1. 當(dāng)你書(shū)寫(xiě) home 值時(shí),鍵入 h 常用的編輯器有智能補(bǔ)全提示;
  2. home 拼寫(xiě)錯(cuò)誤成 hoem,會(huì)有錯(cuò)誤提示,往往這類(lèi)錯(cuò)誤很隱蔽;
  3. 收窄接收的邊界。

函數(shù)類(lèi)型

  • 函數(shù)類(lèi)型不建議直接給 Function 類(lèi)型,有明確的參數(shù)類(lèi)型、個(gè)數(shù)與返回值類(lèi)型最佳。
type FunctionTypes = {onSomething: Function; // ? bad,不推薦。任何可調(diào)用的函數(shù)onClick: () => void; // ? better ,明確無(wú)參數(shù)無(wú)返回值的函數(shù)onChange: (id: number) => void; // ? better ,明確參數(shù)無(wú)返回值的函數(shù)onClick(event: React.MouseEvent<HTMLButtonElement>): void; // ? better
};

可選屬性

  • React props 可選的情況下,比較常用。
type OptionalTypes = {optional?: OptionalType; // 可選屬性
};
  • 例子:封裝一個(gè)第三方組件,對(duì)方可能并沒(méi)有暴露一個(gè) props 類(lèi)型定義時(shí),而你只想關(guān)注自己的上層定義。 nameage 是你新增的屬性,age 可選,other 為第三方的屬性集。
type AppProps = {name: string;age?: number;[propName: string]: any;
};
const YourComponent = ({ name, age, ...other }: AppProps) => (<div>{`Hello, my name is ${name}, ${age || 'unknown'}`}        <Other {...other} /></div>
);

React Prop 類(lèi)型

  • 如果你有配置 Eslint 等一些代碼檢查時(shí),一般函數(shù)組件需要你定義返回的類(lèi)型,或傳入一些 React 相關(guān)的類(lèi)型屬性。
    這時(shí)了解一些 React 自定義暴露出的類(lèi)型就很有必要了。例如常用的 React.ReactNode。
export declare interface AppProps {children1: JSX.Element; // ? bad, 沒(méi)有考慮數(shù)組類(lèi)型children2: JSX.Element | JSX.Element[]; // ? 沒(méi)考慮字符類(lèi)型children3: React.ReactChildren; // ? 名字唬人,工具類(lèi)型,慎用children4: React.ReactChild[]; // better, 但沒(méi)考慮 nullchildren: React.ReactNode; // ? best, 最佳接收所有 children 類(lèi)型functionChildren: (name: string) => React.ReactNode; // ? 返回 React 節(jié)點(diǎn)style?: React.CSSProperties; // React styleonChange?: React.FormEventHandler<HTMLInputElement>; // 表單事件! 泛型參數(shù)即 `event.target` 的類(lèi)型
}

更多參考資料

函數(shù)式組件

熟悉了基礎(chǔ)的 TypeScript 使用 與 React 內(nèi)置的一些類(lèi)型后,我們?cè)撻_(kāi)始著手編寫(xiě)組件了。參考 前端進(jìn)階面試題詳細(xì)解答

  • 聲明純函數(shù)的最佳實(shí)踐
type AppProps = { message: string }; /* 也可用 interface */
const App = ({ message }: AppProps) => <div>{message}</div>; // 無(wú)大括號(hào)的箭頭函數(shù),利用 TS 推斷。
  • 需要隱式 children?可以試試 React.FC。
type AppProps = { title: string };
const App: React.FC<AppProps> = ({ children, title }) => <div title={title}>{children}</div>;
  • 爭(zhēng)議
  1. React.FC(or FunctionComponent)是顯式返回的類(lèi)型,而"普通函數(shù)"版本則是隱式的(有時(shí)還需要額外的聲明)。
  2. React.FC 對(duì)于靜態(tài)屬性如 displayNamepropTypesdefaultProps 提供了自動(dòng)補(bǔ)充和類(lèi)型檢查。
  3. React.FC 提供了默認(rèn)的 children 屬性的大而全的定義聲明,可能并不是你需要的確定的小范圍類(lèi)型。
  4. 2和3都會(huì)導(dǎo)致一些問(wèn)題。有人不推薦使用。

目前 React.FC 在項(xiàng)目中使用較多。因?yàn)榭梢酝祽?#xff0c;還沒(méi)碰到極端情況。

Hooks

項(xiàng)目基本上都是使用函數(shù)式組件和 React Hooks。
接下來(lái)介紹常用的用 TS 編寫(xiě) Hooks 的方法。

useState

  • 給定初始化值情況下可以直接使用
import { useState } from 'react';
// ...
const [val, toggle] = useState(false);
// val 被推斷為 boolean 類(lèi)型
// toggle 只能處理 boolean 類(lèi)型
  • 沒(méi)有初始值(undefined)或初始 null
type AppProps = { message: string };
const App = () => {const [data] = useState<AppProps | null>(null);// const [data] = useState<AppProps | undefined>();return <div>{data && data.message}</div>;
};
  • 更優(yōu)雅,鏈?zhǔn)脚袛?/li>
// data && data.message
data?.message

useEffect

  • 使用 useEffect 時(shí)傳入的函數(shù)簡(jiǎn)寫(xiě)要小心,它接收一個(gè)無(wú)返回值函數(shù)或一個(gè)清除函數(shù)。
function DelayedEffect(props: { timerMs: number }) {const { timerMs } = props;useEffect(() =>setTimeout(() => {/* do stuff */}, timerMs),[timerMs]);// ? bad example! setTimeout 會(huì)返回一個(gè)記錄定時(shí)器的 number 類(lèi)型// 因?yàn)楹?jiǎn)寫(xiě),箭頭函數(shù)的主體沒(méi)有用大括號(hào)括起來(lái)。return null;
}
  • 看看 useEffect接收的第一個(gè)參數(shù)的類(lèi)型定義。
// 1. 是一個(gè)函數(shù)
// 2. 無(wú)參數(shù)
// 3. 無(wú)返回值 或 返回一個(gè)清理函數(shù),該函數(shù)類(lèi)型無(wú)參數(shù)、無(wú)返回值 。
type EffectCallback = () => (void | (() => void | undefined));
  • 了解了定義后,只需注意加層大括號(hào)。
function DelayedEffect(props: { timerMs: number }) {const { timerMs } = props;useEffect(() => {const timer = setTimeout(() => {/* do stuff */}, timerMs);// 可選return () => clearTimeout(timer);}, [timerMs]);// ? 確保函數(shù)返回 void 或一個(gè)返回 void|undefined 的清理函數(shù)return null;
}
  • 同理,async 處理異步請(qǐng)求,類(lèi)似傳入一個(gè) () => Promise<void>EffectCallback 不匹配。
// ? bad
useEffect(async () => {const { data } = await ajax(params);// todo
}, [params]);
  • 異步請(qǐng)求,處理方式:
// ? better
useEffect(() => {(async () => {const { data } = await ajax(params);// todo})();
}, [params]);// 或者 then 也是可以的
useEffect(() => {ajax(params).then(({ data }) => {// todo});
}, [params]);

useRef

useRef 一般用于兩種場(chǎng)景

  1. 引用 DOM 元素;

  2. 不想作為其他 hooks 的依賴(lài)項(xiàng),因?yàn)?ref 的值引用是不會(huì)變的,變的只是 ref.current。

  • 使用 useRef ,可能會(huì)有兩種方式。
const ref1 = useRef<HTMLElement>(null!);
const ref2 = useRef<HTMLElement | null>(null);
  • 非 null 斷言 null!。斷言之后的表達(dá)式非 null、undefined
function MyComponent() {const ref1 = useRef<HTMLElement>(null!);useEffect(() => {doSomethingWith(ref1.current);// 跳過(guò) TS null 檢查。e.g. ref1 && ref1.current});return <div ref={ref1}> etc </div>;
}
  • 不建議使用 !,存在隱患,Eslint 默認(rèn)禁掉。
function TextInputWithFocusButton() {// 初始化為 null, 但告知 TS 是希望 HTMLInputElement 類(lèi)型// inputEl 只能用于 input elementsconst inputEl = React.useRef<HTMLInputElement>(null);const onButtonClick = () => {// TS 會(huì)檢查 inputEl 類(lèi)型,初始化 null 是沒(méi)有 current 上是沒(méi)有 focus 屬性的// 你需要自定義判斷! if (inputEl && inputEl.current) {inputEl.current.focus();}// ? bestinputEl.current?.focus();};return (<><input ref={inputEl} type="text" /><button onClick={onButtonClick}>Focus the input</button></>);
}

useReducer

使用 useReducer 時(shí),多多利用 Discriminated Unions 來(lái)精確辨識(shí)、收窄確定的 typepayload 類(lèi)型。
一般也需要定義 reducer 的返回類(lèi)型,不然 TS 會(huì)自動(dòng)推導(dǎo)。

  • 又是一個(gè)聯(lián)合類(lèi)型收窄和避免拼寫(xiě)錯(cuò)誤的精妙例子。
const initialState = { count: 0 };// ? bad,可能傳入未定義的 type 類(lèi)型,或碼錯(cuò)單詞,而且還需要針對(duì)不同的 type 來(lái)兼容 payload
// type ACTIONTYPE = { type: string; payload?: number | string };// ? good
type ACTIONTYPE =| { type: 'increment'; payload: number }| { type: 'decrement'; payload: string }| { type: 'initial' };function reducer(state: typeof initialState, action: ACTIONTYPE) {switch (action.type) {case 'increment':return { count: state.count + action.payload };case 'decrement':return { count: state.count - Number(action.payload) };case 'initial':return { count: initialState.count };default:throw new Error();}
}function Counter() {const [state, dispatch] = useReducer(reducer, initialState);return (<>Count: {state.count}            <button onClick={() => dispatch({ type: 'decrement', payload: '5' })}>-</button><button onClick={() => dispatch({ type: 'increment', payload: 5 })}>+</button></>);
}

useContext

一般 useContextuseReducer 結(jié)合使用,來(lái)管理全局的數(shù)據(jù)流。

  • 例子
interface AppContextInterface {state: typeof initialState;dispatch: React.Dispatch<ACTIONTYPE>;
}const AppCtx = React.createContext<AppContextInterface>({state: initialState,dispatch: (action) => action,
});
const App = (): React.ReactNode => {const [state, dispatch] = useReducer(reducer, initialState);return (<AppCtx.Provider value={{ state, dispatch }}><Counter /></AppCtx.Provider>);
};// 消費(fèi) context
function Counter() {const { state, dispatch } = React.useContext(AppCtx);return (<>Count: {state.count}            <button onClick={() => dispatch({ type: 'decrement', payload: '5' })}>-</button><button onClick={() => dispatch({ type: 'increment', payload: 5 })}>+</button></>);
}

自定義 Hooks

Hooks 的美妙之處不只有減小代碼行的功效,重點(diǎn)在于能夠做到邏輯與 UI 分離。做純粹的邏輯層復(fù)用。

  • 例子:當(dāng)你自定義 Hooks 時(shí),返回的數(shù)組中的元素是確定的類(lèi)型,而不是聯(lián)合類(lèi)型??梢允褂?const-assertions 。
export function useLoading() {const [isLoading, setState] = React.useState(false);const load = (aPromise: Promise<any>) => {setState(true);return aPromise.finally(() => setState(false));};return [isLoading, load] as const; // 推斷出 [boolean, typeof load],而不是聯(lián)合類(lèi)型 (boolean | typeof load)[]
}
  • 也可以斷言成 tuple type 元組類(lèi)型。
export function useLoading() {const [isLoading, setState] = React.useState(false);const load = (aPromise: Promise<any>) => {setState(true);return aPromise.finally(() => setState(false));};return [isLoading, load] as [boolean, (aPromise: Promise<any>) => Promise<any>];
}
  • 如果對(duì)這種需求比較多,每個(gè)都寫(xiě)一遍比較麻煩,可以利用泛型定義一個(gè)輔助函數(shù),且利用 TS 自動(dòng)推斷能力。
function tuplify<T extends any[]>(...elements: T) {return elements;
}function useArray() {const numberValue = useRef(3).current;const functionValue = useRef(() => {}).current;return [numberValue, functionValue]; // type is (number | (() => void))[]
}function useTuple() {const numberValue = useRef(3).current;const functionValue = useRef(() => {}).current;return tuplify(numberValue, functionValue); // type is [number, () => void]
}

擴(kuò)展

工具類(lèi)型

學(xué)習(xí) TS 好的途徑是查看優(yōu)秀的文檔和直接看 TS 或類(lèi)庫(kù)內(nèi)置的類(lèi)型。這里簡(jiǎn)單做些介紹。

  • 如果你想知道某個(gè)函數(shù)返回值的類(lèi)型,你可以這么做
// foo 函數(shù)原作者并沒(méi)有考慮會(huì)有人需要返回值類(lèi)型的需求,利用了 TS 的隱式推斷。
// 沒(méi)有顯式聲明返回值類(lèi)型,并 export,外部無(wú)法復(fù)用
function foo(bar: string) {return { baz: 1 };
}// TS 提供了 ReturnType 工具類(lèi)型,可以把推斷的類(lèi)型吐出
type FooReturn = ReturnType<typeof foo>; // { baz: number }
  • 類(lèi)型可以索引返回子屬性類(lèi)型
function foo() {return {a: 1,b: 2,subInstArr: [{c: 3,d: 4,},],};
}type InstType = ReturnType<typeof foo>;
type SubInstArr = InstType['subInstArr'];
type SubIsntType = SubInstArr[0];const baz: SubIsntType = {c: 5,d: 6, // type checks ok!
};// 也可一步到位
type SubIsntType2 = ReturnType<typeof foo>['subInstArr'][0];
const baz2: SubIsntType2 = {c: 5,d: 6, // type checks ok!
};

同理工具類(lèi)型 Parameters 也能推斷出函數(shù)參數(shù)的類(lèi)型。

  • 簡(jiǎn)單的看看實(shí)現(xiàn):關(guān)鍵字 infer
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;

T extends (...args: any) => infer R ? R : any; 的意思是 T 能夠賦值給 (...args: any) => any 的話,就返回該函數(shù)推斷出的返回值類(lèi)型 R。

defaultProps

默認(rèn)值問(wèn)題。

type GreetProps = { age: number } & typeof defaultProps;
const defaultProps = {age: 21,
};const Greet = (props: GreetProps) => {// etc
};
Greet.defaultProps = defaultProps;
  • 你可能不需要 defaultProps
type GreetProps = { age?: number };const Greet = ({ age = 21 }: GreetProps) => { // etc 
};

消除魔術(shù)數(shù)字/字符

本人比較痛恨的一些代碼點(diǎn)。

  • 糟糕的例子,看到下面這段代碼不知道你的內(nèi)心,有沒(méi)有羊駝奔騰。
if (status === 0) {// ...
} else {// ...
}// ...if (status === 1) {// ...
}
  • 利用枚舉,統(tǒng)一注釋且語(yǔ)義化
// enum.ts
export enum StatusEnum {Doing,   // 進(jìn)行中Success, // 成功Fail,    // 失敗
}//index.tsx
if (status === StatusEnum.Doing) {// ...
} else {// ...
}// ...if (status === StatusEnum.Success) {// ...
}
  • ts enum 略有爭(zhēng)議,有的人推崇去掉 ts 代碼依舊能正常運(yùn)行,顯然 enum 不行。
// 對(duì)象常量
export const StatusEnum = {Doing: 0,   // 進(jìn)行中Success: 1, // 成功Fail: 2,    // 失敗
};
  • 如果字符單詞本身就具有語(yǔ)義,你也可以用字符字面量聯(lián)合類(lèi)型來(lái)避免拼寫(xiě)錯(cuò)誤
export declare type Position = 'left' | 'right' | 'top' | 'bottom';
let position: Position;// ...// TS2367: This condition will always return 'false' since the types 'Position' and '"lfet"' have no overlap.
if (position === 'lfet') { // 單詞拼寫(xiě)錯(cuò)誤,往往這類(lèi)錯(cuò)誤比較難發(fā)現(xiàn)// ...
}

延伸:策略模式消除 if、else

if (status === StatusEnum.Doing) {return '進(jìn)行中';
} else if (status === StatusEnum.Success) {return '成功';
} else {return '失敗';
}
  • 策略模式
// 對(duì)象常量
export const StatusEnumText = {[StatusEnum.Doing]: '進(jìn)行中',[StatusEnum.Success]: '成功',[StatusEnum.Fail]: '失敗',
};// ...
return StatusEnumText[status];
http://www.risenshineclean.com/news/50127.html

相關(guān)文章:

  • 合同模板網(wǎng)站周口網(wǎng)站建設(shè)公司
  • 眉山 網(wǎng)站開(kāi)發(fā)事件營(yíng)銷(xiāo)的經(jīng)典案例
  • 企業(yè)建網(wǎng)站能不能一次進(jìn)費(fèi)用九幺seo優(yōu)化神器
  • 合肥建站企業(yè)百度指數(shù)的數(shù)據(jù)怎么導(dǎo)出
  • 怎樣做網(wǎng)站編輯校園推廣方案
  • 提供營(yíng)銷(xiāo)網(wǎng)站建設(shè)公司百度推廣收費(fèi)標(biāo)準(zhǔn)
  • 鄭州鄭州網(wǎng)站建設(shè)河南做網(wǎng)站公司哪家好seo建站還有市場(chǎng)嗎
  • 衡水專(zhuān)業(yè)網(wǎng)站制作seo搜索引擎優(yōu)化崗位要求
  • 上饒建設(shè)培訓(xùn)中心網(wǎng)站圖片外鏈生成
  • 蘭州網(wǎng)站建設(shè)招聘信息策劃公司
  • 網(wǎng)頁(yè)制作背景圖代碼杭州seo網(wǎng)站建設(shè)
  • 在家做網(wǎng)站查網(wǎng)址
  • 查詢(xún)商品價(jià)格走勢(shì)的網(wǎng)站自己建網(wǎng)站怎么弄
  • 網(wǎng)站微信認(rèn)證費(fèi)用多少錢(qián)八上數(shù)學(xué)優(yōu)化設(shè)計(jì)答案
  • seo做的不好的網(wǎng)站免費(fèi)網(wǎng)絡(luò)推廣平臺(tái)
  • r6300v2做網(wǎng)站搜索排名廣告營(yíng)銷(xiāo)
  • 做出口網(wǎng)站鄭州新聞發(fā)布
  • 建設(shè)工程材料網(wǎng)站百度seo怎么優(yōu)化
  • 做廚柜有招聘網(wǎng)站嗎seo網(wǎng)站關(guān)鍵字優(yōu)化
  • 紙牌網(wǎng)站建設(shè)德陽(yáng)seo
  • 網(wǎng)頁(yè)設(shè)計(jì)的注意事項(xiàng)網(wǎng)絡(luò)網(wǎng)站推廣優(yōu)化
  • 怎么在programmableweb 網(wǎng)站做api分析圖表深圳百度國(guó)際大廈
  • 所有做網(wǎng)站公司營(yíng)銷(xiāo)廣告文案
  • 外貿(mào)網(wǎng)站該怎么做營(yíng)銷(xiāo)存在的問(wèn)題及改進(jìn)
  • 爾雅網(wǎng)站開(kāi)發(fā)實(shí)戰(zhàn)百度站長(zhǎng)工具網(wǎng)站提交
  • 廣告公司做的網(wǎng)站字體侵權(quán)武漢seo首頁(yè)
  • 美國(guó)做deals的網(wǎng)站中山百度推廣公司
  • 吉林省水土保持生態(tài)建設(shè)網(wǎng)站網(wǎng)站seo優(yōu)化方案設(shè)計(jì)
  • 關(guān)于做網(wǎng)站的調(diào)查問(wèn)卷外包公司
  • 鎮(zhèn)江疫情最新數(shù)據(jù)seo免費(fèi)外鏈工具