自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

TypeScript 中高級(jí)應(yīng)用與完美實(shí)踐

新聞 前端
當(dāng)我們討論 TypeScript 時(shí),我們?cè)谟懻撌裁??TypeScript 中的 Decorator 較為特殊,為 Angular 團(tuán)隊(duì)和 TypeScript 團(tuán)隊(duì)交易的結(jié)果,有興趣可自行搜索相關(guān)資料。

 當(dāng)我們討論 TypeScript 時(shí),我們?cè)谟懻撌裁矗?/p>

TypeScript 的定位

  • JavaScript 的超集
  • 編譯期行為
  • 不引入額外開(kāi)銷
  • 不改變運(yùn)行時(shí)行為
  • 始終與 ESMAScript 語(yǔ)言標(biāo)準(zhǔn)一致 (stage 3 語(yǔ)法)

TypeScript 中的 Decorator 較為特殊,為 Angular 團(tuán)隊(duì)和 TypeScript 團(tuán)隊(duì)交易的結(jié)果,有興趣可自行搜索相關(guān)資料。而且近期 EcmaScript 規(guī)范中的 decorator 提案內(nèi)容發(fā)生了劇烈變動(dòng),建議等此語(yǔ)法標(biāo)準(zhǔn)完全穩(wěn)定后再在生產(chǎn)項(xiàng)目中使用。

本文只討論圖中藍(lán)色部分。

類型的本質(zhì)是契約

JSDoc 也能標(biāo)注類型,為什么要用 TypeScript?

  • JSDoc 只是注釋,其標(biāo)注沒(méi)有約束作用
  • TS 有—checkJs 選項(xiàng),但不好用

TS 會(huì)自動(dòng)推斷函數(shù)返回值類型,為什么要多此一舉標(biāo)注出來(lái)?

  • 契約高于實(shí)現(xiàn)
  • 檢查返回值是否寫錯(cuò)
  • 寫 return 時(shí)獲得提醒

開(kāi)始之前

幾組 VSCode 快捷鍵

  • 代碼補(bǔ)全 control + 空格 ctrl + 空格
  • 快速修復(fù) command + . ctrl + .
  • 重構(gòu)(重命名) fn + f2 f2

一個(gè)網(wǎng)站

TypeScript Playground

初始化項(xiàng)目

自行配置

  1. "compilerOptions": { 
  2.     "esModuleInterop"true
  3.     "allowSyntheticDefaultImports"true
  4.     "noImplicitAny"true
  5.     "strictNullChecks"true
  6.     "noImplicitThis"true
  7.     "moduleResolution""node" 
  8.   

react 項(xiàng)目運(yùn)行 create-react-app ${項(xiàng)目名} —scripts-version=react-scripts-ts

小試牛刀

&和 | 操作符

雖然在寫法上,這兩個(gè)操作符與位運(yùn)算邏輯操作符相同。但在語(yǔ)義上,它們與位運(yùn)算剛好相反。

位運(yùn)算的表現(xiàn):

  1. 1001 | 1010 = 1011    // 合并1 
  2. 1001 & 1010 = 1000    // 只保留共有1 

在 TypeScript 中的表現(xiàn):

  1. interface IA { 
  2.     a: string 
  3.     b: number 
  4.   
  5. type TB = { 
  6.     b: number 
  7.     c: number[] 
  8.   
  9. type TC = IA | TB;    // TC類型的變量的鍵只需包含ab或bc即可,當(dāng)然也可以abc都有 
  10. type TD = IA & TB;    // TD類型的變量的鍵必需包含abc 

對(duì)于這種表現(xiàn),可以這樣理解: & 表示必須同時(shí)滿足多個(gè)契約, | 表示滿足任意一個(gè)契約即可。

interface 和 type 關(guān)鍵字

interface 和 type 兩個(gè)關(guān)鍵字因?yàn)槠涔δ鼙容^接近,常常引起新手的疑問(wèn):應(yīng)該在什么時(shí)候用 type,什么時(shí)候用 interface?

interface 的特點(diǎn)如下:

  • 同名 interface 自動(dòng)聚合,也可以和已有的同名 class 聚合,適合做 polyfill
  • 自身只能表示 object/class/function 的類型

建議庫(kù)的開(kāi)發(fā)者所提供的公共 api 應(yīng)該盡量用 interface/class,方便使用者自行擴(kuò)展。舉個(gè)例子,我之前在給騰訊云 Cloud Studio 在線編輯器開(kāi)發(fā)插件時(shí),因?yàn)椴殚喌降?monaco 文檔是 0.15.5 版本(當(dāng)時(shí)的最新版本)的,而 Cloud Studio 使用的 monaco 版本為 0.14.3,缺失了一些我需要的 API,所以需要手動(dòng) polyfill 一下。

  1. /** 
  2.  * Cloud Studio使用的monaco版本較老0.14.3,和官方文檔相比缺失部分功能 
  3.  * 另外vscode有一些特有的功能,必須適配 
  4.  * 故在這里手動(dòng)實(shí)現(xiàn)作為補(bǔ)充 
  5.  */ 
  6. declare module monaco { 
  7.   interface Position { 
  8.     delta(deltaLineNumber?: number, deltaColumn?: number): Position 
  9.   } 
  10.   
  11. // monaco 0.15.5 
  12. monaco.Position.prototype.delta = function (this: monaco.Position, deltaLineNumber = 0, deltaColumn = 0) { 
  13.   return new monaco.Position(this.lineNumber + deltaLineNumber, this.column + deltaColumn); 
  14.   

與 interface 相比,type 的特點(diǎn)如下:

  • 表達(dá)功能更強(qiáng)大,不局限于 object/class/function
  • 要擴(kuò)展已有 type 需要?jiǎng)?chuàng)建新 type,不可以重名
  • 支持更復(fù)雜的類型操作
  1. type Tuple = [number, string]; 
  2. const a: Tuple = [2'sir']; 
  3. type Size = 'small' | 'default' | 'big' | number; 
  4. const b: Size = 24

基本上所有用 interface 表達(dá)的類型都有其等價(jià)的 type 表達(dá)。但我在實(shí)踐的過(guò)程中,也發(fā)現(xiàn)了一種類型只能用 interface 表達(dá),無(wú)法用 type 表達(dá),那就是往函數(shù)上掛載屬性。

  1. interface FuncWithAttachment { 
  2.     (param: string): boolean
  3.     someProperty: number; 
  4.   
  5. const testFunc: FuncWithAttachment = ...; 
  6. const result = testFunc('mike');    // 有類型提醒 
  7. testFunc.someProperty = 3;    // 有類型提醒 

extends 關(guān)鍵字

extends 本意為 “拓展”,也有人稱其為 “繼承”。在 TypeScript 中,extends 既可當(dāng)作一個(gè)動(dòng)詞來(lái)擴(kuò)展已有類型;也可當(dāng)作一個(gè)形容詞來(lái)對(duì)類型進(jìn)行條件限定(例如用在泛型中)。在擴(kuò)展已有類型時(shí),不可以進(jìn)行類型沖突的覆蓋操作。例如,基類型中鍵 a 為 string,在擴(kuò)展出的類型中無(wú)法將其改為 number。

  1. type A = { 
  2.     a: number 
  3.   
  4. interface AB extends A { 
  5.     b: string 
  6. // 與上一種等價(jià) 
  7. type TAB = A & { 
  8.     b: string 

泛型

在前文我們已經(jīng)看到類型實(shí)際上可以進(jìn)行一定的運(yùn)算,要想寫出的類型適用范圍更廣,不妨讓它像函數(shù)一樣可以接受參數(shù)。TS 的泛型便是起到這樣的作用,你可以把它當(dāng)作類型的參數(shù)。它和函數(shù)參數(shù)一樣,可以有默認(rèn)值。除此之外,還可以用 extends 對(duì)參數(shù)本身需要滿足的條件進(jìn)行限制。

在定義一個(gè)函數(shù)、type、interface、class 時(shí),在名稱后面加上<> 表示即接受類型參數(shù)。而在實(shí)際調(diào)用時(shí),不一定需要手動(dòng)傳入類型參數(shù),TS 往往能自行推斷出來(lái)。在 TS 推斷不準(zhǔn)時(shí),再手動(dòng)傳入?yún)?shù)來(lái)糾正。

  1. // 定義 
  2. class React.Component<P = {}, S = {}, SS = any> { ... } 
  3. interface IShowConfig<P extends IShowProps> { ... } 
  4. // 調(diào)用 
  5. class Modal extends React.Component<IModalProps, IModalState> { ... } 

條件類型

除了與、或等基本邏輯,TS 的類型也支持條件運(yùn)算,其語(yǔ)法與三目運(yùn)算符相同,為 T extends U ? X : Y 。這里先舉一個(gè)簡(jiǎn)單的例子。在后文中我們會(huì)看到很多復(fù)雜類型的實(shí)現(xiàn)都需要借助條件類型。

  1. type IsEqualType<A, B> = A extends B ? (B extends A ? true : false) : false
  2. type NumberEqualsToString = IsEqualType<number, string>;   // false 
  3. type NumberEqualsToNumber = IsEqualType<number, number>;    // true 

環(huán)境 Ambient Modules

在實(shí)際應(yīng)用開(kāi)發(fā)時(shí)有一種場(chǎng)景,當(dāng)前作用域下可以訪問(wèn)某個(gè)變量,但這個(gè)變量并不由開(kāi)發(fā)者控制。例如通過(guò) Script 標(biāo)簽直接引入的第三方庫(kù) CDN、一些宿主環(huán)境的 API 等。這個(gè)時(shí)候可以利用 TS 的環(huán)境聲明功能,來(lái)告訴 TS 當(dāng)前作用域可以訪問(wèn)這些變量,以獲得類型提醒。

具體有兩種方式,declare 和三斜線指令。

  1. declare const IS_MOBILE = true;    // 編譯后此行消失 
  2. const wording = IS_MOBILE ? '移動(dòng)端' : 'PC端'

用三斜線指令可以一次性引入整個(gè)類型聲明文件。

  1. /// <reference path="../typings/monaco.d.ts" /> 
  2. const range = new monaco.Range(2367); 

深入類型系統(tǒng)

基本類型

基本類型,也可以理解為原子類型。包括 number、boolean、string、null、undefined、function、array、字面量(true,false,1,2,‘a’)等。它們無(wú)法再細(xì)分。

復(fù)合類型

TypeScript 的復(fù)合類型可以分為兩類: set 和 map 。set 是指一個(gè)無(wú)序的、無(wú)重復(fù)元素的集合。而 map 則和 JS 中的對(duì)象一樣,是一些沒(méi)有重復(fù)鍵的鍵值對(duì)。

  1. // set 
  2. type Size = 'small' | 'default' | 'big' | 'large'
  3. // map 
  4. interface IA { 
  5.     a: string 
  6.     b: number 

復(fù)合類型間的轉(zhuǎn)換

  1. // map => set 
  2. type IAKeys = keyof IA;    // 'a' | 'b' 
  3. type IAValues = IA[keyof IA];    // string | number 
  4.   
  5. // set => map 
  6. type SizeMap = { 
  7.     [k in Size]: number 
  8. // 等價(jià)于 
  9. type SizeMap2 = { 
  10.     small: number 
  11.     default: number 
  12.     big: number 
  13.     large: number 

map 上的操作

  1. // 索引取值 
  2. type SubA = IA['a'];    // string     
  3.   
  4. // 屬性修飾符 
  5. type Person = { 
  6.     age: number 
  7.     readonly name: string    // 只讀屬性,初始化時(shí)必須賦值 
  8.     nickname?: string    // 可選屬性,相當(dāng)于 | undefined 

映射類型和同態(tài)變換

在 TypeScript 中,有以下幾種常見(jiàn)的映射類型。它們的共同點(diǎn)是只接受一個(gè)傳入類型,生成的類型中 key 都來(lái)自于 keyof 傳入的類型,value 都是傳入類型的 value 的變種。

  1. type Partial<T> = { [P in keyof T]?: T[P] }    // 將一個(gè)map所有屬性變?yōu)榭蛇x的 
  2. type Required<T> = { [P in keyof T]-?: T[P] }    // 將一個(gè)map所有屬性變?yōu)楸剡x的 
  3. type Readonly<T> = { readonly [P in keyof T]: T[P] }    // 將一個(gè)map所有屬性變?yōu)橹蛔x的 
  4. type Mutable<T> = { -readonly [P in keyof T]: T[P] }    // ts標(biāo)準(zhǔn)庫(kù)未包含,將一個(gè)map所有屬性變?yōu)榭蓪懙?/span> 

此類變換,在 TS 中被稱為同態(tài)變換。在進(jìn)行同態(tài)變換時(shí),TS 會(huì)先復(fù)制一遍傳入?yún)?shù)的屬性修飾符,再應(yīng)用定義的變換。

  1. interface Fruit { 
  2.     readonly name: string 
  3.     size: number 
  4. type PF = Partial<Fruit>;    // PF.name既只讀又可選,PF.size只可選 

其他常用工具類型

由 set 生成 map

  1. type Record<K extends keyof any, T> = { [P in K]: T }; 
  2.   
  3. type Size = 'small' | 'default' | 'big'
  4. /* 
  5. { 
  6.     small: number 
  7.     default: number 
  8.     big: number 
  9. } 
  10.  */ 
  11. type SizeMap = Record<Size, number>; 

保留 map 的一部分

  1. type Pick<T, K extends keyof T> = { [P in K]: T[P] }; 
  2. /* 
  3. { 
  4.     default: number 
  5.     big: number 
  6. } 
  7.  */ 
  8. type BiggerSizeMap = Pick<SizeMap, 'default' | 'big'>; 
  9.   

刪除 map 的一部分

  1. type Omit<T, K> = Pick<T, Exclude<keyof T, K>>; 
  2. /* 
  3. { 
  4.     default: number 
  5. } 
  6.  */ 
  7. type DefaultSizeMap = Omit<BiggerSizeMap, 'big'>; 

保留 set 的一部分

  1. type Extract<T, U> = T extends U ? T : never; 
  2.   
  3. type Result = 1 | 2 | 3 | 'error' | 'success'
  4. type StringResult = Extract<Result, string>;    // 'error' | 'success 

刪除 set 的一部分

  1. type Exclude<T, U> = T extends U ? never : T; 
  2. type NumericResult = Exclude<Result, string>;    // 1 | 2 | 3 

獲取函數(shù)返回值的類型。但要注意不要濫用這個(gè)工具類型,應(yīng)該盡量多手動(dòng)標(biāo)注函數(shù)返回值類型。理由開(kāi)篇時(shí)提過(guò), 契約高于實(shí)現(xiàn) 。用 ReturnType 是由實(shí)現(xiàn)反推契約,而實(shí)現(xiàn)往往容易變且容易出錯(cuò),契約則相對(duì)穩(wěn)定。另一方面,ReturnType 過(guò)多也會(huì)降低代碼可讀性。

  1. type ReturnType<T> = T extends (...args: any[]) => infer R ?  R : any; 
  2.   
  3. function f() { return { a: 3, b: 2}; } 
  4. /* 
  5. { 
  6.     a: number 
  7.     b: number 
  8. } 
  9.  */ 
  10. type FReturn = ReturnType<f>; 

以上這些工具類型都已經(jīng)包含在了 TS 標(biāo)準(zhǔn)庫(kù)中,在應(yīng)用中直接輸入名字進(jìn)行使用即可。另外,在這些工具類型的實(shí)現(xiàn)中,出現(xiàn)了 infer、never、typeof 等關(guān)鍵字,在后文我會(huì)詳細(xì)解釋它們的作用。

類型的遞歸

TS 原生的 Readonly 只會(huì)限制一層寫入操作,我們可以利用遞歸來(lái)實(shí)現(xiàn)深層次的 Readonly。但要注意,TS 對(duì)最大遞歸層數(shù)做了限制,最多遞歸 5 層。

  1. type DeepReadony<T> = { 
  2.     readonly [P in keyof T]: DeepReadony<T[P]> 
  3.   
  4. interface SomeObject { 
  5.   a: { 
  6.     b: { 
  7.       c: number; 
  8.     }; 
  9.   }; 
  10.   
  11. const obj: Readonly<SomeObject> = { a: { b: { c: 2 } } }; 
  12. obj.a.b.c = 3;    // TS不會(huì)報(bào)錯(cuò) 
  13.   
  14. const obj2: DeepReadony<SomeObject> = { a: { b: { c: 2 } } }; 
  15. obj2.a.b.c = 3;    // Cannot assign to 'c' because it is a read-only property. 

never infer typeof 關(guān)鍵字

never 是 | 運(yùn)算的幺元,即 x | never = x 。例如之前的 Exclude<Result, string> 運(yùn)算過(guò)程如下:

infer 的作用是讓 TypeScript 自己推斷,并將推斷的結(jié)果存儲(chǔ)到一個(gè)臨時(shí)名字中,并且只能用于 extends 語(yǔ)句中。它與泛型的區(qū)別在于,泛型是聲明一個(gè) “參數(shù)”,而 infer 是聲明一個(gè) “中間變量”。infer 我用得比較少,這里借用一下官方的示例。

  1. type Unpacked<T> = 
  2.     T extends (infer U)[] ? U : 
  3.     T extends (...args: any[]) => infer U ? U : 
  4.     T extends Promise<infer U> ? U : 
  5.     T; 
  6.   
  7. type T0 = Unpacked<string>;  // string 
  8. type T1 = Unpacked<string[]>;  // string 
  9. type T2 = Unpacked<() => string>;  // string 
  10. type T3 = Unpacked<Promise<string>>;  // string 
  11. type T4 = Unpacked<Promise<string>[]>;  // Promise<string> 
  12. type T5 = Unpacked<Unpacked<Promise<string>[]>>;  // string 

typeof 用于獲取一個(gè) “常量” 的類型,這里的 “常量” 是指任何可以在編譯期確定的東西,例如 const、function、class 等。它是從 實(shí)際運(yùn)行代碼 通向 類型系統(tǒng) 的單行道。理論上,任何運(yùn)行時(shí)的符號(hào)名想要為類型系統(tǒng)所用,都要加上 typeof。但是 class 比較特殊不需要加,因?yàn)?ts 的 class 出現(xiàn)得比 js 早,現(xiàn)有的為兼容性解決方案。

在使用 class 時(shí), class 名 表示實(shí)例類型, typeof class 表示 class 本身類型。沒(méi)錯(cuò),這個(gè)關(guān)鍵字和 js 的 typeof 關(guān)鍵字重名了 :)。

  1. const config = { width: 2, height: 2 }; 
  2. function getLength(str: string) { return str.length; } 
  3.   
  4. type TConfig = typeof config;    // { width: number, height: number } 
  5. type TGetLength = typeof getLength;    // (str: string) => number 

實(shí)戰(zhàn)演練

我在項(xiàng)目中遇到這樣一種場(chǎng)景,需要獲取一個(gè)類型中所有 value 為指定類型的 key。例如,已知某個(gè) React 組件的 props 類型,我需要 “知道”(編程意義上)哪些參數(shù)是 function 類型。

  1. interface SomeProps { 
  2.     a: string 
  3.     b: number 
  4.     c: (e: MouseEvent) => void 
  5.     d: (e: TouchEvent) => void 
  6. // 如何得到 'c' | 'd' ?  

分析一下這里的思路,我們需要從一個(gè) map 得到一個(gè) set,而這個(gè) set 是 map 的 key 的 子集,篩選子集的 條件 是 value 的類型。要構(gòu)造 set 的子集,需要用到 never ;要實(shí)現(xiàn)條件判斷,需要用到 extends ;而要實(shí)現(xiàn) key 到 value 的訪問(wèn),則需要索引取值。經(jīng)過(guò)一些嘗試后,解決方案如下。

  1. type GetKeyByValueType<T, Condition> = { 
  2.     [K in keyof T]: T[K] extends Condition ? K : never 
  3. } [keyof T]; 
  4.   
  5. type FunctionPropNames =  GetKeyByValueType<SomeProps, Function>;    // 'c' | 'd' 

這里的運(yùn)算過(guò)程如下:

  1. // 開(kāi)始 
  2.     a: string 
  3.     b: number 
  4.     c: (e: MouseEvent) => void 
  5.     d: (e: TouchEvent) => void 
  6. // 第一步,條件映射 
  7.     a: never 
  8.     b: never 
  9.     c: 'c' 
  10.     d: 'd' 
  11. // 第二步,索引取值 
  12. never | never | 'c' | 'd' 
  13. // never的性質(zhì) 
  14. 'c' | 'd' 

編譯提示 Compiler Hints

TypeScript 只發(fā)生在編譯期,因此我們可以在代碼中加入一些符號(hào),來(lái)給予編譯器一些提示,使其按我們要求的方式運(yùn)行。

類型轉(zhuǎn)換

類型轉(zhuǎn)換的語(yǔ)法為 < 類型名> xxx 或 xxx as 類型名 。推薦始終用 as 語(yǔ)法,因?yàn)榈谝环N語(yǔ)法無(wú)法在 tsx 文件使用,而且容易和泛型混淆。一般只有這幾種場(chǎng)景需要使用類型轉(zhuǎn)換:自動(dòng)推斷不準(zhǔn);TS 報(bào)錯(cuò),想不出更好的類型編寫方法,手動(dòng)抄近路;臨時(shí) “放飛自我”。

在使用類型轉(zhuǎn)換時(shí),應(yīng)該遵守幾個(gè)原則:

  • 若要放松限制,只可放松到能運(yùn)行的最嚴(yán)格類型上
  • 如果不知道一個(gè)變量的精確類型,只標(biāo)注到大概類型(例如 any[])也比 any 好
  • 任何一段 “放飛自我”(完全沒(méi)有類型覆蓋)區(qū)代碼不應(yīng)超過(guò) 2 行,應(yīng)在出現(xiàn)第一個(gè)可以確定類型的變量時(shí)就補(bǔ)上標(biāo)注

在編寫 TS 程序時(shí),我們的目標(biāo)是讓類型覆蓋率無(wú)限接近 100%。

! 斷言

! 的作用是斷言某個(gè)變量不會(huì)是 null / undefined,告訴編譯器停止報(bào)錯(cuò)。這里由用戶確保斷言的正確。它和剛剛進(jìn)入 EcmaScript 語(yǔ)法提案 stage 3 的 Optional Chaining 特性不同。Optional Chaining 特性可以保證訪問(wèn)的安全性,即使在 undefined 上訪問(wèn)某個(gè)鍵也不會(huì)拋出異常。而 ! 只是消除編譯器報(bào)錯(cuò),不會(huì)對(duì)運(yùn)行時(shí)行為造成任何影響。

  1. // TypeScript 
  2. mightBeUndefined!.a = 2 
  3. // 編譯為 
  4. mightBeUndefined.a = 2 

// @ts-ignore

用于忽略下一行的報(bào)錯(cuò),盡量少用。

其他

我為什么不提 enum

enum 在 TS 中出現(xiàn)的比較早,它引入了 JavaScript 沒(méi)有的數(shù)據(jù)結(jié)構(gòu)(編譯成一個(gè)雙向 map),入侵了運(yùn)行時(shí),與 TypeScript 宗旨不符。用 string literal union('small' | 'big' | 'large')可以做到相同的事,且在 debug 時(shí)可讀性更好。如果很在意條件比較的性能,應(yīng)該用二進(jìn)制 flag 加位運(yùn)算。

  1. // TypeScript 
  2. enum Size { 
  3.     small = 3
  4.     big, 
  5.     large 
  6. const a:Size = Size.large;    // 5 
  7.   
  8. // 編譯為 
  9. var Size; 
  10. (function (Size) { 
  11.     Size[Size["small"] = 3] = "small"
  12.     Size[Size["big"] = 4] = "big"
  13.     Size[Size["large"] = 5] = "large"
  14. })(Size || (Size = {})); 
  15. const a = Size.large; // 5 

寫在最后

應(yīng)該以什么心態(tài)來(lái)編寫 TypeScript

我們應(yīng)該編寫有類型系統(tǒng)的 JavaScript,而不是能編譯成 JavaScript 的 Java/C#。任何一個(gè) TypeScript 程序,在手動(dòng)刪去類型部分,將后綴改成 .js 后,都應(yīng)能夠正常運(yùn)行。

責(zé)任編輯:張燕妮 來(lái)源: alloyteam.com
相關(guān)推薦

2021-09-09 07:21:26

TypeScript 高級(jí)類型

2009-12-16 16:02:21

華為無(wú)線路由器配置

2019-07-03 10:29:59

JavaScript算法程序員

2009-08-02 10:21:39

ASP.NET程序員面ASP.NET

2010-04-07 10:31:05

鴻海郭臺(tái)銘

2025-02-27 08:00:00

熔斷機(jī)制微服務(wù)Spring

2019-02-20 14:10:22

2024-09-11 08:10:46

2021-03-13 07:49:27

OLTPOLAP數(shù)據(jù)庫(kù)

2023-09-21 22:02:22

Go語(yǔ)言高級(jí)特性

2025-01-14 00:10:00

Java應(yīng)用程序

2025-03-28 06:01:00

TypeScript泛型開(kāi)發(fā)

2023-12-06 13:18:00

物聯(lián)網(wǎng)

2012-04-26 17:57:36

應(yīng)用安全

2012-04-26 18:59:43

防火墻WEB應(yīng)用防火墻沙龍

2020-06-17 18:10:01

TypeScript前端

2012-12-24 09:49:08

SaaSSaaS安全

2023-08-24 08:11:39

斷路器監(jiān)控報(bào)警

2024-03-07 07:31:20

畫像標(biāo)簽算法業(yè)務(wù)數(shù)據(jù)

2010-08-25 08:58:32

HTML
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)