在上一篇我重點講述了 ts 的交叉類型,本期將結合實例重點講述 ts 中的一些高級操做符。本篇文章略長,筆者以前的文章都略短,做爲男人仍是要好好學習,文章仍是長點好。javascript
本期涉及的操做符以下:html
本篇文章適合有必定基礎的 ts 開發,若是你徹底沒有用過,請先到官網學習官方文檔, java
經過上述操做符的學習,但願能達到如下效果:git
下面我將結合具體實慄向你們講述 ts 中的高級操做符。github
keyof與Object.keys略有類似,只是 keyof 是取 interface 的鍵,並且 keyof 取到鍵後會保存爲聯合類型。typescript
interface iUserInfo {
name: string;
age: number;
}
type keys = keyof iUserInfo;
複製代碼
咱們有這樣一個需求,實現一個函數 getValue 取得對象的 value。在未接觸 keyof 時,咱們通常會這樣寫:數組
function getValue(o: object, key: string) {
return o[key];
}
const obj1 = { name: '張三', age: 18 };
const name = getValue(obj1, 'name');
複製代碼
可是,這樣寫就喪失了 ts 的優點:bash
這時咱們可使用 keyof 來加強 getValue 函數的類型功能。async
function getValue<T extends Object, K extends keyof T>(o: T, key: K): T[K] {
return o[key];
}
const obj1 = { name: '張三', age: 18 };
const a = getValue(obj1, 'hh');
複製代碼
in用於取聯合類型的值。主要用於數組和對象的構造。函數
type name = 'firstName' | 'lastName';
type TName = {
[key in name]: string;
};
複製代碼
const data1 = [
{
a1: 'a',
b1: 'b',
c1: 'c',
d1: 'd',
},
];
const data2 = [
{
a2: 'a',
b2: 'b',
},
];
複製代碼
但切記不要用於 interface,不然會出錯
先看官方解釋:
Within the extends clause of a conditional type, it is now possible to have infer declarations that introduce a type variable to be inferred. Such inferred type variables may be referenced in the true branch of the conditional type. It is possible to have multiple infer locations for the same type variable.
翻譯過來就是:
如今在有條件類型的 extends 子語句中,容許出現 infer 聲明,它會引入一個待推斷的類型變量。 這個推斷的類型變量能夠在有條件類型的 true 分支中被引用。 容許出現多個同類型變量的 infer。
初步看來,這個 ts 關鍵字限制比較多,也是筆者以爲比較難理解的,可是它對咱們獲取一些比較複雜的類型特別有用。使用過程當中須要注意如下幾個關鍵點:
要完全理解這個關鍵詞的使用必須結合一些實例。
好比咱們這裏定義了一個函數類型 TArea,如今要實現將函數的參數類型取出來,咱們該怎麼作呢?
type TArea = (width: number, height: number) => number;
type params = Parameters<TArea>;
複製代碼
其實 Parameters 方法 ts 已內置,源碼以下:
type Parameters<T extends (...args: any) => any> = T extends (
...args: infer P
) => any
? P
: never;
複製代碼
咱們仔細研讀一下以上源碼,發現遵循咱們上面所說的 infer 知足的四個特色:
這裏再囉嗦幾句,由於咱們要獲取函數參數,因此傳遞的參數必須是個函數,因此有 T extends (...args: any) => any
,因爲咱們要獲取的是函數參數的類型,因此 infer 出如今了函數參數位置。
同理獲取函數返回值的方法就呼之欲出了,若是仍是寫不出來,當我沒說。
ReturnType 方法 ts 已內置
type ReturnType<T extends (...args: any) => any> = T extends (
...args: any
) => infer R
? R
: any;
複製代碼
再看一下圖,不要說我騙你!
了不起了,infer 真是太強大了,下面咱們繼續看 infer 如何獲取一個類實例的類型。
type InstanceType<T extends new (...args: any) => any> = T extends new (
...args: any
) => infer R
? R
: any;
複製代碼
偷偷告訴你,聰明的 ts 官方也內置了這個工具。
該方法 ts 已內置咱們看一下源碼
type ConstructorParameters<
T extends new (...args: any) => any
> = T extends new (...args: infer P) => any ? P : never;
複製代碼
咱們能夠這樣使用它
type ThisParameterType<T> = T extends (this: infer U, ...args: any[]) => any
? U
: unknown;
複製代碼
實現效果以下,你們能夠本身手動實現一下,這能夠很好的訓練一下 infer 的使用。
type OmitThisParameter<T> = unknown extends ThisParameterType<T>
? T
: T extends (...args: infer A) => infer R
? (...args: A) => R
: T;
複製代碼
咱們能夠這樣理解:若是傳遞的函數不包含 this 參數,則直接返回。如下語法用於判斷是否包含 this 參數
unknown extends ThisParameterType<T>
複製代碼
咱們重點講述了 ts 中 keyof 和 infer 的高級用法,下面以兩個思考題結束本篇文章,具體答案會在下篇文章揭曉。
這是一道 leetcode 的 ts筆試題,原題目略長,就不直接貼出來了,這裏簡化一下:
// 假設有一個這樣的類型:
interface initInterface {
count: number;
message: string;
asyncMethod<T, U>(input: Promise<T>): Promise<Action<U>>;
syncMethod<T, U>(action: Action<T>): Action<U>;
}
// 在通過 Connect 函數以後,返回值類型爲
type Result {
asyncMethod<T, U>(input: T): Action<U>;
syncMethod<T, U>(action: T): Action<U>;
}
// 其中 Action<T> 的定義爲:
interface Action<T> {
payload?: T
type: string
}
// 如今要求寫出Connect的函數類型定義。
複製代碼
// 有原數組以下
const data1 = [
{
a1: 'a',
b1: 'b',
c1: 'c'
}
];
// 實現一個函數 transformData ,傳遞一個keyMap後,結果返回通過keyMap轉換後的數組
const A2 = transformData(data1, { a1: 'a2' }); // 返回 [{a2: 'a'}]
const A2 = transformData(data1, { a1: 'a2',b2: 'b1' }); // 返回 [{a2: 'a', b2: 'b']
// 要求用ts完成,必須有完善類型推斷,不能出現any
複製代碼
@Author: WaterMan