前言: 本文章爲 TypeScript 系列文章. 旨在利用碎片時間快速入門 Typescript. 或從新溫故 Typescript 查漏補缺.在官方 api 的基礎上, 加上一些平常使用的感想. 若是感興趣的話~ 歡迎關注, 後續持續推出文章.javascript
文章列表:前端
目錄結構:java
javascript 做爲一門動態語言, 在實際運行的時候,等變量被賦值才知道該變量的類型. 動態語言給實際的編碼帶來了很大的靈活性.react
function getVal(val) {
retrurn val;
}
getVal(1) // 返回數字類型
getVal('1') // 返回字符串類型
getVal(['2']) // 返回數組類型
複製代碼
可是一樣的, 在代碼運行期間有可能會發生與類型相關的錯誤, 下降了代碼的可維護性. 那下面咱們用 typescript 來定義變量. 爲了支持3種調用方式, 咱們須要聲明三種類型定義. 有2種方法能夠解決上面這個問題.程序員
function getVal(val: number): number
function getVal(val: string):string
function getVal(val: any):any {
return val;
}
複製代碼
function getVal(val: string | number | any[]):string | number | any[] {
return val;
}
複製代碼
做爲一個程序員, 上面2種方法讓咱們感覺重複繁瑣. 這是沒法容忍的. 那怎麼樣可讓該函數又能夠在運行的時候被賦值才肯定該變量的類型, 又有必定的類型約束減小相關的錯誤? 答案就是: 泛型ajax
function getVal<T>(val: T): T {
return val;
}
複製代碼
T 即表明捕獲函數傳入的參數類型, 而後在函數內部使用 T 即用該參數類型聲明其餘變量. 可是咱們從上面的函數看出, 由於 T 是捕獲參數傳入的參數類型,typescript
而這個函數能夠傳入任意參數, 與咱們最開始只支持3個類型的需求不符. 因此下面要引入泛型約束.api
type Params= string | number | any[];
function getVal<T extends Params>(val: T): T {
return val;
}
getVal(1);
getVal('2');
getVal(['222']);
getVal<number>('3'); // 跟泛型指定的類型不一致, 報錯
getVal({}); // 不是 Param 類型, 報錯
複製代碼
泛型便可以聲明函數, 也能夠聲明類. 也能夠聲明接口數組
class Person<T>{} // 一個尖括號跟在類名後面
function Person<T> {} // 一個尖括號跟在函數名後面
interface Person<T> {} // 一個尖括號跟在接口名後面
複製代碼
有些時候, 一個類或者一個函數裏面, 他不止要用到一個動態類型, 他要用到多個. 可是咱們上面只能捕獲一個, 那直接聲明多個不就行了?bash
function getName<T,U> (name: T, id: U): [T, U] {
return [name, id]
}
getName('peen', 1);
getName('peen', '222'); // 正常
getName<string, number>('peen', '22'); // 報錯: '22'不是number類型
複製代碼
在實際項目中, 每一個項目都須要接口請求, 咱們會封裝一個通用的接口請求, 在這個函數裏面, 處理一些常見的錯誤等等. 爲了讓每一個接口調用都有 typescript 約束, 提醒. 這裏使用泛型是很是合適了.
interface IApiSourceParams {
GetList: IGetList
}
interface IGetList {
id: number;
}
export function fetchApi<T extends keyof IApiSourceParams>(action: T, params: IApiSourceParams[T]) {
return ajax({
url: action,
method: 'POST',
body: params
})
}
fetchApi('GetList', { id: 2 });
fetchApi('GetList', { id: '33' }); // 報錯, id 應該是 number 類型
複製代碼
這樣子, 咱們就給一個通用的接口請求函數增長了類型約束. 在 IApiSourceParams 中擴展每個接口類型便可.
從上面的例子看到了 T extends keyof IApiSourceParams , 這在上文中沒有看到. 實際這種應用場景特別多.
索引類型查詢操做符: keyof , 對於任何類型 T, keyof T的結果爲 T上已知的公共屬性名的聯合. 看着話有點繞, 直接看例子吧
interface Person {
name: string;
age: number;
}
let personProps: keyof Person; // 'name' | 'age'
複製代碼
索引訪問操做符 : T[K] . 上面的 keyof 實際就是獲取了對象的鍵值, 看一下上面的實際例子
interface IApiSourceParams {
GetList: IGetList,
PostApi: IPostApi
}
interface IGetList {
id: number;
}
export function fetchApi<T extends keyof IApiSourceParams>(action: T, params: IApiSourceParams[T]) {
return ajax({
url: action,
method: 'POST',
body: params
})
}
// IApiSourceParams[T] 獲取的即是接口 IApiSourceParams 對應key值的接口 IGetList.
複製代碼
泛型在各大庫中都很是普遍的使用, 下面選react中的類和react hook 實地分析
1、react 類
若是使用過 react , 確定見過下面這種語法聲明 props 和 state
class Test extends Component<IProps, IState> {}
複製代碼
咱們再看看 react class 裏面的 typescript 聲明
class Component<P, S> {
static contextType?: Context<any>;
context: any;
constructor(props: Readonly<P>);
constructor(props: P, context?: any);
setState<K extends keyof S>(
state: ((prevState: Readonly<S>, props: Readonly<P>) => (Pick<S, K> | S | null)) | (Pick<S, K> | S | null),
callback?: () => void
): void;
forceUpdate(callBack?: () => void): void;
render(): ReactNode;
readonly props: Readonly<P> & Readonly<{ children?: ReactNode }>;
state: Readonly<S>;
refs: {
[key: string]: ReactInstance
};
}
複製代碼
能夠看到react以及提早幫忙作好了一些約束
2、React HOOK
咱們隨便找一個最常使用的 useState 方法.
function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];
function useState<S = undefined>(): [S | undefined, Dispatch<SetStateAction<S | undefined>>];
複製代碼
因此咱們在使用的時候, 能夠
const [errorMessage, setError] = useState<string>('');
複製代碼
本篇文章講了泛型解決的場景以及語法. 並介紹了一些實際的應用場景. 最後歡迎關注「前端加加」,認真學前端,作個有專業的技術人...