TypeScript類型級(jí)別和值級(jí)別示例詳解
對(duì)值級(jí)別編程類型級(jí)別編程區(qū)分
首先,讓我們對(duì)值級(jí)別編程和類型級(jí)別編程進(jìn)行重要區(qū)分。
- 值級(jí)別編程讓我們編寫將在生產(chǎn)中運(yùn)行的代碼即運(yùn)行期,并為我們的用戶提供有用的東西。
- 類型級(jí)別編程幫助我們確保代碼在發(fā)布之前即編譯期不包含錯(cuò)誤,在運(yùn)行期會(huì)被完全刪除
JavaScript沒(méi)有類型,所以所有JavaScript都是值級(jí)別的代碼:
// A simple Javascript function:
function sum(a, b) {
return a + b;
}
TypeScript允許我們將類型注釋添加到JavaScript中,并確保我們編寫的sum函數(shù)永遠(yuǎn)不會(huì)用數(shù)字以外的任何東西調(diào)用:
// Using type annotations:
function sum(a: number, b: number): number {
return a + b;
}
但TypeScript的類型系統(tǒng)遠(yuǎn)比這強(qiáng)大得多。我們編寫的真實(shí)代碼有時(shí)需要是通用的,并接受我們事先不知道的類型。
在這種情況下,我們可以在尖括號(hào)<A,B,…>中定義類型參數(shù)然后,我們可以將類型參數(shù)傳遞給一個(gè)類型級(jí)函數(shù),該函數(shù)根據(jù)輸入類型計(jì)算輸出類型:
// Using type level programming:
function genericFunction<A, B>(a: A, b: B): DoSomething<A, B> {
return doSomething(a, b);
}
這就是類型級(jí)編程!DoSomething<A,B> 是一種用特殊編程語(yǔ)言編寫的類型級(jí)函數(shù),它與我們用于值的語(yǔ)言不同,但同樣強(qiáng)大。讓我們將這種語(yǔ)言稱為類型級(jí)TypeScript。
// This is a type-level function: type DoSomething<A, B> = ... // This is a value-level function: const doSomething = (a, b) => ...
類型級(jí)編程
類型級(jí)TypeScript是一種最小的純函數(shù)語(yǔ)言。
在類型級(jí)別,函數(shù)被稱為泛型類型:它們接受一個(gè)或多個(gè)類型參數(shù)并返回單個(gè)輸出類型。下面是一個(gè)函數(shù)的簡(jiǎn)單示例,該函數(shù)使用兩個(gè)類型參數(shù)并將它們包裝在元組中:
type SomeFunction<A, B> = [A, B];
/* ---- ------
^ \
type return type
parameters
\-------------------------/
^
Generic
*/
類型級(jí)別的TypeScript沒(méi)有很多功能。畢竟,它是專門為你的代碼做類型約束的!也就是說(shuō),它確實(shí)有足夠的特性(幾乎)圖靈完備,這意味著你可以用它解決任意復(fù)雜的問(wèn)題。
- 代碼分支:根據(jù)條件執(zhí)行不同的代碼路徑(相當(dāng)于值級(jí)別if/else關(guān)鍵字)。
- 變量賦值:聲明一個(gè)變量并在表達(dá)式中使用它(相當(dāng)于值級(jí)別var/let關(guān)鍵字)。
- 函數(shù):可重復(fù)使用的邏輯單位,如我們?cè)谇懊娴氖纠锌吹降摹?/li>
- 循環(huán):通常通過(guò)遞歸。
- 相等檢查:==但適用于類型!
- 還有更多!
這是我們將在接下來(lái)的章節(jié)中學(xué)習(xí)的語(yǔ)言類型的簡(jiǎn)要概述?,F(xiàn)在,讓我們開(kāi)始第一次挑戰(zhàn)吧!
挑戰(zhàn)是如何工作的
在每一章結(jié)束時(shí),你將有一些挑戰(zhàn)需要解決,以將你的新技能付諸實(shí)踐。它們看起來(lái)像這樣:
namespace challenge {
// 1. implement a generic to get the union
// of all keys in an object type.
type GetAllKeys<Obj> = TODO;
type res1 = GetAllKeys<{ a: number }>;
type test1 = Expect<Equal<res1, "a">>;
}
namespace是一個(gè)鮮為人知的TypeScript功能,它可以讓我們?cè)趯S梅秶鷥?nèi)隔離每個(gè)挑戰(zhàn)。TODO是占位符。這是您需要更換的!res1=。。。是泛型為某些輸入類型返回的類型。您可以用鼠標(biāo)將其懸停以檢查其當(dāng)前type test1=Expect<Equal<res1,…>>是類型級(jí)單元測(cè)試。用于判斷TODO部分的代碼是否正確
在此之前你要先定義好Expect和Equal
type Expect<T extends true> = T;
type Equal<X, Y> = (<T>() => T extends { [k in keyof X]: X[k]; } ? 1 : 2) extends <T>() => T extends { [k in keyof Y]: Y[k]; } ? 1 : 2 ? true : false;
挑戰(zhàn)
準(zhǔn)備好迎接你的第一個(gè)挑戰(zhàn)了嗎?出發(fā):
/**
* 1. The `identity` function takes a value of any type
* and returns it. Make it generic!
*/
namespace genericFunction {
function identity(a: TODO): TODO {
return a;
}
let input1 = 10;
let res1 = identity(input1);
type test1 = Expect<Equal<typeof res1, number>>;
let input2 = "Hello";
let res2 = identity(input2);
type test2 = Expect<Equal<typeof res2, string>>;
}
/**
* 2. `safeHead` takes an array, a default value
and returns the first element of the array
if it isn't empty. Make it generic!
*/
namespace safeHead {
function safeHead(array: TODO[], defaultValue: TODO): TODO {
return array[0] ?? defaultValue;
}
let input1 = [1, 2, 3];
let res1 = safeHead(input1, 0);
type test1 = Expect<Equal<typeof res1, number>>;
let input2 = ["Hello", "Hola", "Bonjour"];
let res2 = safeHead(input2, "Hi");
type test2 = Expect<Equal<typeof res2, string>>;
}
/**
* 3. `map` transforms all values in an array to a value of
* different type. Make it generic!
*/
namespace map {
function map(array: TODO[], fn: (value: TODO) => TODO): TODO[] {
return array.map(fn);
}
let input1 = [1, 2, 3];
let res1 = map(input1, value => value.toString());
type test1 = Expect<Equal<typeof res1, string[]>>;
let input2 = ["Hello", "Hola", "Bonjour"];
let res2 = map(input2, str => str.length);
type test2 = Expect<Equal<typeof res2, number[]>>;
}
/**
* 4. `pipe2` takes a value and pipes it into 2 functions
* sequentially. For example, `pipe2(x, f1, f2)` will
* result in `f2(f1(x))`. Make it generic!
*
*/
namespace pipe2 {
function pipe2(
x: TODO,
f1: (value: TODO) => TODO,
f2: (value: TODO) => TODO
): TODO {
return f2(f1(x));
}
let res1 = pipe2(
[1, 2, 3],
arr => arr.length,
length => `length: ${length}`
);
type test1 = Expect<Equal<typeof res1, string>>;
let res2 = pipe2(
{ name: 'Alice' },
user => user.name,
name => name.length > 5
);
type test2 = Expect<Equal<typeof res2, boolean>>;
}以上就是TypeScript類型級(jí)別和值級(jí)別示例詳解的詳細(xì)內(nèi)容,更多關(guān)于TypeScript類型級(jí)別值級(jí)別的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
TypeScript判斷對(duì)稱的二叉樹(shù)方案詳解
這篇文章主要為大家介紹了TypeScript判斷對(duì)稱的二叉樹(shù)方案實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09
TypeScript使用strictnullcheck實(shí)戰(zhàn)解析
這篇文章主要為大家介紹了TypeScript使用strictnullcheck實(shí)戰(zhàn)解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08
詳解什么是TypeScript里的Constructor?signature
這篇文章主要介紹了什么是TypeScript里的Constructor?signature詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07
Typescript?extends?關(guān)鍵字繼承類型約束及條件類型判斷實(shí)現(xiàn)示例解析
這篇文章主要介紹了Typescript?extends?關(guān)鍵字繼承類型約束及條件類型判斷實(shí)現(xiàn)示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08
TypeScript逆變之條件推斷和泛型的應(yīng)用示例詳解
這篇文章主要為大家介紹了TypeScript逆變之條件推斷和泛型的應(yīng)用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09

