TypeScript類型聲明書寫詳解
本文總結(jié)一下TypeScript類型聲明的書寫,很多時候?qū)慣ypeScript不是問題,寫類型就特別糾結(jié),我總結(jié)下,我在使用TypeScript中遇到的問題。如果你遇到類型聲明不會寫的時候,多看看lodash的聲明,因為lodash對數(shù)據(jù)進行各種變形操作,所以你能遇到的,都有參考示例。
基本類型
// 變量 const num: number = 1; const str: string = 'str'; const bool: boolean = true; const nulls: null = null; const undefine: undefined = undefined; const symbols: symbol = Symbol('symbal'); const any: any = 'any types'; // typescript的any類型,相當于什么類型約束都沒有
數(shù)組
// 數(shù)組: 推薦使用T[]這種寫法 const nums: number[] = [1, 2, 3, 4]; // 不推薦:Array<T>泛型寫法,因為在JSX中不兼容,所以為了統(tǒng)一都使用T[]這種類型 const strs: Array<string> = ['s', 't', 'r']; const dates: Date[] = [new Date(), new Date()];
數(shù)組的concat方法,返回類型為never[]問題
// 數(shù)組concat方法的never問題 // 提示: Type 'string' is not assignable to type 'never'. const arrNever: string[] = [].concat(['s']); // 主要問題是:[]數(shù)組,ts無法根據(jù)上下文判斷數(shù)組內(nèi)部元素的類型 // @see https://github.com/Microsoft/TypeScript/issues/10479 const fixArrNever: string[] = ([] as string[]).concat(['s']);
接口
接口是 TypeScript 的一個核心知識,它能合并眾多類型聲明至一個類型聲明:
而且接口可以用來聲明:函數(shù),類,對象等數(shù)據(jù)類型
interface Name { first: string; second: string; } let username: Name = { first: 'John', second: 'Doe' };
any、null、undefined、void類型
// 特殊類型 const any: any = 'any types'; // typescript的any類型,相當于什么類型都沒寫 let nobody: any = 'nobody, but you'; nobody = 123; let nulls: number = null; let bool: boolean = undefined; // void function printUsername (name: string): void { console.log(name); }
聯(lián)合類型
聯(lián)合類型在option bags模式場景非常實用,使用 **| **來做標記
function options(opts: { types?: string; tag: string | number; }): void { }
交叉類型
最典型的使用場景就是繼承和mixin,或者copy等操作
// 交叉類型:如果以后遇到此種類型聲明不會寫,直接看Object.assign聲明寫法 function $extend<T, U>(first: T, second: U): T & U { return Object.assign(first, second); // 示意而已 }
元組 tuple
元組很少使用
let nameNumber: [string, number]; // Ok nameNumber = ['Jenny', 221345]; // Error // nameNumber = ['Jenny', '221345']; let tuple: [string, number]; nameNumber = ['Jenny', 322134]; const [usernameStr, uselessNum] = nameNumber;
type的作用
ype用來創(chuàng)建新的類型,也可以重命名(別名)已有的類型,建議使用type創(chuàng)建簡單類型,無嵌套的或者一層嵌套的類型,其它復雜的類型都應(yīng)該使用interface, 結(jié)合implements ,extends實現(xiàn)。
type StrOrNum = string | number; // 使用 let sample: StrOrNum; sample = 123; sample = '123'; // 會檢查類型 sample = true; // Error
實踐中遇到的問題
第三方庫沒有提供聲明d.ts文件
如果第三方庫沒有提供聲明文件,第一時間去微軟官方的倉庫https://github.com/borisyankov/DefinitelyTyped 查找,或者在npmjs.com上搜索@types/依賴的模塊名大部分情況都可以找到。
手動添加聲明文件
聲明文件一般都是統(tǒng)一放置在types文件夾下
// 例子: types/axios.d.ts declare module 'axios'; // 這里的axios聲明為any類型
全局變量
例如一些庫直接把在window上添加的全局變量
// globals.d.ts // 例子:jQuery,現(xiàn)實中jQuery是有.d.ts declare const jQuery: any; declare const $: typeof jQuery;
非JavaScript資源
在前端工程中,import很多非js資源,例如:css, html, 圖片,vue, 這種ts無法識別的資源時,就需要告訴ts,怎么識別這些導入的資源的類型。
// 看看vue怎么處理的:shims-vue.d.ts declare module '*.vue' { import Vue from 'vue'; export default Vue; } // html declare module '*.html'; // css declare module '*.css';
強制類型轉(zhuǎn)換
有時候遇到需要強制類型轉(zhuǎn)換,尤其是對聯(lián)合類型或者可選屬性時。
// 第一種:使用<>括號 const convertArrType: string[] = <Array<string>>[].concat(['s']); // 第二種:使用as關(guān)鍵字 const fixArrNever: string[] = ([] as string[]).concat(['s']);
建議使用第二種,因為兼容JSX,第一種官方也不推薦了,雖然它是合法的。
可選屬性和默認屬性
API中提供的參數(shù)很多都有默認值,或者屬性可選,怎么書寫呢?
class Socket {} // 聯(lián)合類型 export type SocketType = 'WebSocket' | 'SockJs'; export interface SocketOptions { type: SocketType; protocols?: string | string[]; // 可選 pingMessage: string | (() => string); // 聯(lián)合類型,可以為string或者函數(shù) pongMessage: string | (() => string); } // 默認值 export function eventHandler = ( evt: CloseEvent | MessageEvent | Event, socket: Socket, type = 'WebSocket' // 默認值 ) => any;
獨立函數(shù)怎么聲明類型
剛開始我也很糾結(jié)這個問題,我就是一個獨立的函數(shù),怎么聲明類型呢?尤其是寫事件處理函數(shù)的API時。
class Socket {} // 函數(shù)的聲明方式 export type SocketEventHandler = ( evt: CloseEvent | MessageEvent | Event, socket: Socket ) => any; const eventHandler: SocketEventHandler = (evt, socket) => { } // 可選參數(shù)和rest參數(shù) let baz = (x = 1) => {}; let foo = (x: number, y: number) => {}; let bar = (x?: number, y?: number) => {}; let bas = (...args: number[]) => {};
索引屬性類型聲明
JavaScript中的對象都可以使用字符串索引直接取屬性或者調(diào)用方法,TypeScript中也有相應(yīng)的類型聲明方法。
type Hello = { hello: 'world'; // key只是一個形式屬性名(類似形參一樣) [key: string]: string; }; const greeting: Hello = { hi: 'morning' } console.log(greeting['hi'])
動態(tài)添加的屬性聲明
有的時候我們只聲明了一個基本的類型結(jié)構(gòu),然后后續(xù)有擴展的情況 ,尤其時二次封裝時的options。
interface AxiosOptions {} type AjaxOptions = { axiosOptions: AxiosOptions; // 額外擴展的放入到單獨的屬性節(jié)點下 extraOptions: { [prop: string]: any }; }; type AjaxOptions1 = { axiosOptions?: AxiosOptions; // 不要這樣寫,因為axiosOptions拼寫錯誤時,ts不會提示 // 盡量把后續(xù)擴展的屬性,移動到獨立的屬性節(jié)點下 [prop: string]: any }; const ajaxOptions: AjaxOptions1 = { axiosOptions1: {}; // 本意是axiosOptions,但是ts不會提示 }
!的使用
! 標識符告訴ts編譯器,聲明的變量沒有問題,再運行期不會報錯。
class BaseSelect extends Vue { options: string[]; // 這里會提示沒有在constructor中初始化 created() { this.options = ['inited'] } } class BaseSelect extends Vue { options!: string[]; // 使用 ! 告訴編譯器,我知道自己在做什么 created() { this.options = ['inited'] } }
this的使用
對于獨立使用的函數(shù),可以聲明指定的調(diào)用上下文
class Handler { info: string; // 聲明指定的this上下文 onClickBad(this: Handler, e: Event) { // oops, used this here. using this callback would crash at runtime this.info = e.message; } } let h = new Handler(); uiElement.addClickListener(h.onClickBad); // error!
聲明合并(擴展Vue聲明)
來看看使用場景,擴展vue,在vue上添加全局的屬性。
// vue的聲明在 vue/types/vue.d.ts declare module 'vue/types/vue' { // 相當于Vue.$eventBus interface Vue { $eventBus: Vue; } // 相當于在Vue.prototype.$eventBus interface VueConstructor { $eventBus: Vue; } }
總結(jié)
TypeScript聲明還有很多高級的用法,目前我也沒有用到那么多,在我糾結(jié)不會寫聲明的時候,我就會看看別人的聲明文件時怎么寫的。
注意:盡量不要把解構(gòu)和聲明寫在一起,可讀性極差。
class Node { onNodeCheck(checkedKeys: any, { // 解構(gòu) checked, checkedNodes, node, event, } : { // 聲明 node: any; [key: string]: any; } ) { } }
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
js將網(wǎng)址轉(zhuǎn)為urlencode類型
網(wǎng)址urlencode加密函數(shù),主要用于中文目錄2008-06-06使用堆實現(xiàn)Top K算法(JS實現(xiàn))
這篇文章主要介紹了使用堆實現(xiàn)Top K算法,即JS實現(xiàn),文中詳細介紹了Top K算法,感興趣的小伙伴們可以參考一下2015-12-12