數據類型
js的數據類型有七種:Boolean,Number,Object所灸,Array,null炫七,undefined爬立,Symbol
類型
這里就說幾個比較特別需要注意的點
空值(Void)
在js中沒有空值的概念,在ts中万哪,可以用void表示沒有任何返回值的函數
function alertName():void {
alert("my name is lhy");
}
然而聲明一個void類型的變量沒有什么用侠驯,因為你只能將它賦值為null和undefined。
let undisable: void = undefined;
任意類型(any)
如果是一個普通的類型奕巍,在賦值過程中改變類型是不允許的吟策,但是任意類型是可以的
let anything: any = {} | null |'' | 0
聲明了一個變量為任意值之后,對它的任何操作和返回的內容的類型都是任意值的止。
并且一個變量如果沒有聲明任何一個類型檩坚,那么它默認就是任意類型。(但是我瞅著好像在我代碼里面并不是這樣)
聯合類型
聯合類型使用 | 來分割每個類型。
let test: string | number
訪問聯合屬性的方法:我們必須只能訪問此聯合類型里公用的屬性和方法
錯誤:
function getLength(something: string | number): number {
return something.length;
}
number沒有l(wèi)ength這個屬性
正確:
function getString(something: string | number): string {
return something.toString();
}
所以匾委,聯合類型在被賦值的時候拖叙,會根據類型推論的規(guī)則推斷出一個類型。
對象的類型-interface(接口)
TS中interface是一個很靈活的概念剩檀,除了可以用于對類的一部分行為進行抽象以外憋沿,也常用于對“對象的形狀”進行描述
規(guī)范:接口一般首字母大寫,有的編程語言中會建議接口的名稱加上I前綴
interface IPerson {
name: string;
age: number;
}
let tom: IPerson = {
name: 'Tom',
age: 25
};
這種的接口沪猴,則要求賦值的時候,變量的形狀必須和接口的形狀保持一直采章,如果想要擁有任意的未添加定義的屬性运嗜,可以??
可選屬性/任意屬性
interface Person {
name: string;
age?: number;
[propName: string]: any;
}
這個樣子變量就可以擁有任意的未添加的定義屬性
只讀屬性
有的時候我們希望對象中的一些字段只能在創(chuàng)建的時候被賦值,那么可以用readonly只讀屬性悯舟。
interface IPerson {
readonly id: number;
test: string;
}
let person: IPerson {
id: 123;
test: 'xxx'
}
// 這個時候試圖去改變id的值則會報錯
person.id = 90;
// 報錯5W狻!抵怎!
只讀的約束存在于第一次給對象賦值的時候奋救,而不是第一次給只讀屬性賦值的時候
數組的類型
最簡單的使用方法就是類型+方括號來表示數組:
let test:number[] = [1, 2, 3, 4]
// 這個數組里面只能是數字
數組泛型( 常用)
let test: Array<number> = [1, 2, 4];
用接口來表示數組
interface NumberArray {
[index: number]: number
}
let fibonacci: NumberArray = [1, 1, 2, 3, 5];
函數的類型
函數是js里面最重要的成員之一!反惕!
一個函數有輸入和輸出尝艘,要在ts中對其進行約束,則需要把輸入和輸出都考慮到姿染,最簡單的例子:
let mySum = function (x: number, y: number): number {
return x + y;
};
let mySum: (x: number, y: number) => number = function (x: number, y: number): number {
return x + y;
};
利用接口定義函數的形狀
interface SearchFunc {
(source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
return source.search(subString) !== -1;
}
此外背亥,對于函數而言,可選參數后面不允許再出現必須參數了
錯誤:
function buildName(firstName?: string, lastName: string) {
if (firstName) {
return firstName + ' ' + lastName;
} else {
return lastName;
}
}
// errorP汀=坪骸!C銎摹盾戴!
但是如果我們給參數設置了默認值,那么就不受這個規(guī)則的限制了1唷尖啡!
剩余參數
ES6中,可以使用...reset 的方式獲取函數中的剩余參數中鼠。舉例如下:
function push(array, ...items) {
items.forEach(function(item) {
array.push(item);
});
}
let a = [];
push(a, 1, 2, 3);
函數重載
重載允許一個函數接受不同數量或類型的參數可婶,作出不同的處理。
比如我們需要實現一個reverse函數援雇,輸入數字 123 的時候矛渴,輸出反轉的數字 321,輸入字符串 'hello' 的時候,輸出反轉的字符串 'olleh'具温。
利用聯合類型蚕涤,我們可以這么實現:
function reverse(x: number | y: number): number | string {
if (typeof x === 'number') {
return Number(x.toString().split('').reverse().join(''));
} else if (typeof x === 'string') {
return x.split('').reverse().join('');
}
}
但是這樣寫的話,代碼的可讀性并不是很高铣猩,就是輸入數字的時候揖铜,輸出也應該是數字,輸入字符串的時候达皿,輸出也應該是字符串天吓,這個時候我們可以用重載去定義reverse函數
function reverse(x: number): number;
function reverse(x: string): string;
function reverse(x: number | string): number | string {
if (typeof x === 'number') {
return Number(x.toString().split('').reverse().join(''));
} else if (typeof x === 'string') {
return x.split('').reverse().join('');
}
}
在代碼中我們可以看見,我們重復定義了多次函數 reverse峦椰,前幾次都是函數定義龄寞,最后一次是函數實現。
類型斷言(便捷汤功,不必使用typeof 判斷)
之前有說過物邑,當 TypeScript 不確定一個聯合類型的變量到底是哪個類型的時候,我們只能訪問此聯合類型的所有類型里共有的屬性或方法滔金,而有時候色解,我們確實還是需要在還不確定類型的時候就訪問其中一個類型的屬性或方法,比如
function getLength(something: string | number): number {
if (something.length) {
return something.length;
} else {
return something.toString().length;
}
}
此時會報錯2鸵稹?蒲帧!
/ index.ts(2,19): error TS2339: Property 'length' does not exist on type 'string | number'.
// Property 'length' does not exist on type 'number'.
// index.ts(3,26): error TS2339: Property 'length' does not exist on type 'string | number'.
// Property 'length' does not exist on type 'number'.
這個時候我們可以非常方便的使用類型斷言
function getLength(something: string | number): number {
// 在需要斷言的變量前面增加類型V硬 O羲 !3濉票唆! 避免寫 typeof something === 'string' && something.length 這么復雜了!R倥恰走趋!
if ((<string>something).length) {
return (<string>something).length;
} else {
return something.toString().length;
}
}
聲明文件
通常我們會把聲明語句放在一個單獨的文件里,這就是聲明文件噪伊,例如創(chuàng)建一個聲明文件jQuery.d.ts,里面的聲明語句如下:
declare var JQuery:(selector: string) => any;
一般來說簿煌,ts會解析項目中所有的.ts文件,當然也包含以.d.ts結尾的文件鉴吹,所以當我們將 jQuery.d.ts 放到項目中時姨伟,其他所有 *.ts 文件就都可以獲得 jQuery 的類型定義了。
/path/to/project
├── src
| ├── index.ts
| └── jQuery.d.ts
└── tsconfig.json
加入仍然無法解析豆励,那么可以檢查下tsconfig.json里面的file, include和exclude的配置夺荒。確保其包含了jQuery.d.ts文件瞒渠。
第三方聲明(經常用到)
當然,jQuery 的聲明文件不需要我們定義了技扼,社區(qū)已經幫我們定義好了:jQuery in DefinitelyTyped伍玖。
我們可以直接下載下來使用,但是更推薦的是使用 @types 統(tǒng)一管理第三方庫的聲明文件剿吻。
@types 的使用方式很簡單窍箍,直接用 npm 安裝對應的聲明模塊即可,以 jQuery 舉例:
npm install @types/jquery --save-dev
可以在這個頁面搜索你需要的聲明文件丽旅。在項目里面椰棘,基本上都會用到第三方聲明文件。
但是當一個第三方庫沒有提供我們想要的聲明文件的時候榄笙,我們需要去手動書寫聲明文件晰搀,這樣就得了解聲明語句了。??
手寫聲明文件
理論上來說办斑,會在項目里面建立一個types文件夾,然后將我們所有的聲明文件放在該目錄下杆逗,然后這種方式需要配置tsconfig.json中的paths和bathUrl字段乡翅。
tsconfig.json的配置:
{
"compilerOptions": {
"module": "commonjs",
"baseUrl": "./",
"paths": {
"*": ["types/*"]
}
}
}
內置對象
JS提供的標準對象有:Boolean, error, Date, RegExp等
我們可以在ts中將變量定義為這些類型:
let b: Boolean = new Boolean(1);
let e: Error = new Error('Error occurred');
let d: Date = new Date();
let r: RegExp = /[a-z]/;
DOM和BOM的內置對象
DOM 和 BOM提供的內置對象有:
Document, HTMLElement, Event, NodeList等。
TS中會經常用到這些類型:
let body: HTMLElement = document.body;
let allDiv: NodeList = document.querySelectorAll('div');
document.addEventListener('click', function(e: MouseEvent){
// do something
})
這些類型的定義文件都在ts核心庫定義文件
TS核心庫定義文件
TS核心庫中的定義文件中定義了所有瀏覽器環(huán)境需要用到的類型罪郊,并且是預置在TS中的蠕蚜。
當你在使用一些常用方法的時候,TS實際上已經幫你做了很多類型判斷的工作悔橄。比如:
Math.pow(10, '2');
// index.ts(1,14): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
就是這個函數的兩個參數必須都是Number類型
想要用TS寫node.js
Node.js不是內置對象的一部分靶累,如果想要用Node.js寫TS,則需要引入第三方聲明文件:
npm install @types/node --save