TypeScript類(lèi)型聲明書(shū)寫(xiě)詳解
本文總結(jié)一下TypeScript類(lèi)型聲明的書(shū)寫(xiě),很多時(shí)候?qū)慣ypeScript不是問(wèn)題,寫(xiě)類(lèi)型就特別糾結(jié),我總結(jié)下,我在使用TypeScript中遇到的問(wèn)題。如果你遇到類(lèi)型聲明不會(huì)寫(xiě)的時(shí)候,多看看lodash的聲明,因?yàn)閘odash對(duì)數(shù)據(jù)進(jìn)行各種變形操作,所以你能遇到的,都有參考示例。
基本類(lèi)型
// 變量
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類(lèi)型,相當(dāng)于什么類(lèi)型約束都沒(méi)有
數(shù)組
// 數(shù)組: 推薦使用T[]這種寫(xiě)法 const nums: number[] = [1, 2, 3, 4]; // 不推薦:Array<T>泛型寫(xiě)法,因?yàn)樵贘SX中不兼容,所以為了統(tǒng)一都使用T[]這種類(lèi)型 const strs: Array<string> = ['s', 't', 'r']; const dates: Date[] = [new Date(), new Date()];
數(shù)組的concat方法,返回類(lèi)型為never[]問(wèn)題
// 數(shù)組concat方法的never問(wèn)題 // 提示: Type 'string' is not assignable to type 'never'. const arrNever: string[] = [].concat(['s']); // 主要問(wèn)題是:[]數(shù)組,ts無(wú)法根據(jù)上下文判斷數(shù)組內(nèi)部元素的類(lèi)型 // @see https://github.com/Microsoft/TypeScript/issues/10479 const fixArrNever: string[] = ([] as string[]).concat(['s']);
接口
接口是 TypeScript 的一個(gè)核心知識(shí),它能合并眾多類(lèi)型聲明至一個(gè)類(lèi)型聲明:
而且接口可以用來(lái)聲明:函數(shù),類(lèi),對(duì)象等數(shù)據(jù)類(lèi)型
interface Name {
first: string;
second: string;
}
let username: Name = {
first: 'John',
second: 'Doe'
};
any、null、undefined、void類(lèi)型
// 特殊類(lèi)型
const any: any = 'any types'; // typescript的any類(lèi)型,相當(dāng)于什么類(lèi)型都沒(méi)寫(xiě)
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)合類(lèi)型
聯(lián)合類(lèi)型在option bags模式場(chǎng)景非常實(shí)用,使用 **| **來(lái)做標(biāo)記
function options(opts: {
types?: string;
tag: string | number;
}): void {
}
交叉類(lèi)型
最典型的使用場(chǎng)景就是繼承和mixin,或者copy等操作
// 交叉類(lèi)型:如果以后遇到此種類(lèi)型聲明不會(huì)寫(xiě),直接看Object.assign聲明寫(xiě)法
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用來(lái)創(chuàng)建新的類(lèi)型,也可以重命名(別名)已有的類(lèi)型,建議使用type創(chuàng)建簡(jiǎn)單類(lèi)型,無(wú)嵌套的或者一層嵌套的類(lèi)型,其它復(fù)雜的類(lèi)型都應(yīng)該使用interface, 結(jié)合implements ,extends實(shí)現(xiàn)。
type StrOrNum = string | number; // 使用 let sample: StrOrNum; sample = 123; sample = '123'; // 會(huì)檢查類(lèi)型 sample = true; // Error
實(shí)踐中遇到的問(wèn)題
第三方庫(kù)沒(méi)有提供聲明d.ts文件
如果第三方庫(kù)沒(méi)有提供聲明文件,第一時(shí)間去微軟官方的倉(cāng)庫(kù)https://github.com/borisyankov/DefinitelyTyped 查找,或者在npmjs.com上搜索@types/依賴(lài)的模塊名大部分情況都可以找到。
手動(dòng)添加聲明文件
聲明文件一般都是統(tǒng)一放置在types文件夾下
// 例子: types/axios.d.ts declare module 'axios'; // 這里的axios聲明為any類(lèi)型
全局變量
例如一些庫(kù)直接把在window上添加的全局變量
// globals.d.ts // 例子:jQuery,現(xiàn)實(shí)中jQuery是有.d.ts declare const jQuery: any; declare const $: typeof jQuery;
非JavaScript資源
在前端工程中,import很多非js資源,例如:css, html, 圖片,vue, 這種ts無(wú)法識(shí)別的資源時(shí),就需要告訴ts,怎么識(shí)別這些導(dǎo)入的資源的類(lèi)型。
// 看看vue怎么處理的:shims-vue.d.ts
declare module '*.vue' {
import Vue from 'vue';
export default Vue;
}
// html
declare module '*.html';
// css
declare module '*.css';
強(qiáng)制類(lèi)型轉(zhuǎn)換
有時(shí)候遇到需要強(qiáng)制類(lèi)型轉(zhuǎn)換,尤其是對(duì)聯(lián)合類(lèi)型或者可選屬性時(shí)。
// 第一種:使用<>括號(hào) const convertArrType: string[] = <Array<string>>[].concat(['s']); // 第二種:使用as關(guān)鍵字 const fixArrNever: string[] = ([] as string[]).concat(['s']);
建議使用第二種,因?yàn)榧嫒軯SX,第一種官方也不推薦了,雖然它是合法的。
可選屬性和默認(rèn)屬性
API中提供的參數(shù)很多都有默認(rèn)值,或者屬性可選,怎么書(shū)寫(xiě)呢?
class Socket {}
// 聯(lián)合類(lèi)型
export type SocketType = 'WebSocket' | 'SockJs';
export interface SocketOptions {
type: SocketType;
protocols?: string | string[]; // 可選
pingMessage: string | (() => string); // 聯(lián)合類(lèi)型,可以為string或者函數(shù)
pongMessage: string | (() => string);
}
// 默認(rèn)值
export function eventHandler = (
evt: CloseEvent | MessageEvent | Event,
socket: Socket,
type = 'WebSocket' // 默認(rèn)值
) => any;
獨(dú)立函數(shù)怎么聲明類(lèi)型
剛開(kāi)始我也很糾結(jié)這個(gè)問(wèn)題,我就是一個(gè)獨(dú)立的函數(shù),怎么聲明類(lèi)型呢?尤其是寫(xiě)事件處理函數(shù)的API時(shí)。
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[]) => {};
索引屬性類(lèi)型聲明
JavaScript中的對(duì)象都可以使用字符串索引直接取屬性或者調(diào)用方法,TypeScript中也有相應(yīng)的類(lèi)型聲明方法。
type Hello = {
hello: 'world';
// key只是一個(gè)形式屬性名(類(lèi)似形參一樣)
[key: string]: string;
};
const greeting: Hello = {
hi: 'morning'
}
console.log(greeting['hi'])
動(dòng)態(tài)添加的屬性聲明
有的時(shí)候我們只聲明了一個(gè)基本的類(lèi)型結(jié)構(gòu),然后后續(xù)有擴(kuò)展的情況 ,尤其時(shí)二次封裝時(shí)的options。
interface AxiosOptions {}
type AjaxOptions = {
axiosOptions: AxiosOptions;
// 額外擴(kuò)展的放入到單獨(dú)的屬性節(jié)點(diǎn)下
extraOptions: {
[prop: string]: any
};
};
type AjaxOptions1 = {
axiosOptions?: AxiosOptions;
// 不要這樣寫(xiě),因?yàn)閍xiosOptions拼寫(xiě)錯(cuò)誤時(shí),ts不會(huì)提示
// 盡量把后續(xù)擴(kuò)展的屬性,移動(dòng)到獨(dú)立的屬性節(jié)點(diǎn)下
[prop: string]: any
};
const ajaxOptions: AjaxOptions1 = {
axiosOptions1: {}; // 本意是axiosOptions,但是ts不會(huì)提示
}
!的使用
! 標(biāo)識(shí)符告訴ts編譯器,聲明的變量沒(méi)有問(wèn)題,再運(yùn)行期不會(huì)報(bào)錯(cuò)。
class BaseSelect extends Vue {
options: string[]; // 這里會(huì)提示沒(méi)有在constructor中初始化
created() {
this.options = ['inited']
}
}
class BaseSelect extends Vue {
options!: string[]; // 使用 ! 告訴編譯器,我知道自己在做什么
created() {
this.options = ['inited']
}
}
this的使用
對(duì)于獨(dú)立使用的函數(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!
聲明合并(擴(kuò)展Vue聲明)
來(lái)看看使用場(chǎng)景,擴(kuò)展vue,在vue上添加全局的屬性。
// vue的聲明在 vue/types/vue.d.ts
declare module 'vue/types/vue' {
// 相當(dāng)于Vue.$eventBus
interface Vue {
$eventBus: Vue;
}
// 相當(dāng)于在Vue.prototype.$eventBus
interface VueConstructor {
$eventBus: Vue;
}
}
總結(jié)
TypeScript聲明還有很多高級(jí)的用法,目前我也沒(méi)有用到那么多,在我糾結(jié)不會(huì)寫(xiě)聲明的時(shí)候,我就會(huì)看看別人的聲明文件時(shí)怎么寫(xiě)的。
注意:盡量不要把解構(gòu)和聲明寫(xiě)在一起,可讀性極差。
class Node {
onNodeCheck(checkedKeys: any, { // 解構(gòu)
checked, checkedNodes, node, event,
} : { // 聲明
node: any;
[key: string]: any;
}
) {
}
}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
D3.js實(shí)現(xiàn)繪制折線(xiàn)圖的教程詳解
這篇文章主要為大家詳細(xì)介紹了如何通過(guò)D3.js實(shí)現(xiàn)繪制折線(xiàn)圖,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)D3.js有一定的幫助,需要的可以參考一下2022-11-11
精通Javascript系列之Javascript基礎(chǔ)篇
javascrpit的基本概念分析,剛開(kāi)始學(xué)習(xí)js的朋友可以參考下。2011-06-06
Bootstrap Metronic完全響應(yīng)式管理模板之菜單欄學(xué)習(xí)筆記
這篇文章主要介紹了Bootstrap Metronic完全響應(yīng)式管理模板之菜單欄學(xué)習(xí)筆記,感興趣的小伙伴們可以參考一下2016-07-07
JavaScript 語(yǔ)句之常用 for 循環(huán)詳解
這篇文章主要介紹了JavaScript 語(yǔ)句之常用 for 循環(huán),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03
Promise.all中對(duì)于reject的處理方法
這篇文章主要介紹了Promise.all中對(duì)于reject的處理方法,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-08-08

