在ts中,類型系統被設計爲可選的,因此可以認爲js就是沒有類型聲明的ts。
類型註解使用 :TypeAnnotation
語法
原始類型
let num: number;
let str: string;
let bool: boolean;
:number
、:string
、:boolean
都是原始類型
數組
原始類型和[]
結合,就是數組類型,如:number[]
、:string[]
、:boolean[]
let boolArray: boolean[];
boolArray = [true, false];
let strArray: string[];
strArray = ['1', '2'];
let numArray: number[];
numArray = [1,2]
內聯類型
內聯類型和數組類型有點像,數組是:typeAnnotation[]
,內聯是:{ /* Structure */}
let name: {
first: string;
second: string;
};
name = {
first: 'John',
second: 'Doe'
};
內聯類型能爲我們快速提供類型註釋。如果需要多次使用相同的內聯註解時,可以使用下面要說的接口。
接口
接口是ts類型系統的核心,這裏先做簡單介紹。接口可以認爲是把多個類型合併爲一個新的類型。
interface name {
first: string;
second: string;
}
let name1:name = {
first: 'a',
second: 'b'
}
let name2:name = {
first: 'aa',
second: 'bb'
}
特殊類型
特殊類型包括any
、 null
、 undefined
以及 void
當我們把類型定義爲any,等同於關閉了ts類型檢查,因此任何類型都能賦予給他。在把js遷移到ts的時候,經常會使用到他。但過多的使用any就失去了類型檢查的意義,因此應該減少使用。
let power: any;
// 賦值任意類型
power = '123';
power = 123;
除了any類型,null和undefined也可以賦值給任意類型
// "strictNullChecks": false, 該值默認爲true
let num: number;
let str: string;
// 這些類型能被賦予
num = null;
str = undefined;
void類型
:void
表示函數沒有返回值。
function log(message: string): void {
console.log(message);
}
泛型
在說泛型前,讓我們先看一個實際的場景:假設有個函數,它接收一個列表,並且返回這個列表的反向排序。
function reverse(items) {
const toreturn = [];
for (let i = items.length - 1; i >= 0; i--) {
toreturn.push(items[i]);
}
return toreturn;
}
let reversed = reverse([1,2,3]); // [3,2,1]
let reversed1 = reverse(['1', '2', '3']); // ['3', '2', '1']
如果沒有泛型,爲上面的函數添加類型就比較困難(當然也可以用聯合類型),因爲輸入的列表項可能是字符串、數字或者其他類型。使用泛型可以輕鬆解決。
function reverse<T>(items: T[]): T[] {
const toreturn = [];
for (let i = items.length - 1; i >= 0; i--) {
toreturn.push(items[i]);
}
return toreturn;
}
泛型用<T>
表示,T可以是任意字符。reverse函數接受類型爲T的數組,數組的每一項類型爲T,數組的返回值類型爲T。當我們傳入[1, 2, 3]
時,TypeScript 能推斷出 reverse 爲 number[]
類型,從而能給你類型安全。與此相似,傳入['1', '2', '3']
時,TypeScript 能推斷 reverse 爲 string[] 類型
聯合類型
聯合類型用|
表示,顧名思義,他可以表示多種不同的類型。
function formatCommandline(command: string[] | string) {
let line = '';
if (typeof command === 'string') {
line = command.trim();
} else {
line = command.join(' ').trim();
}
}
上面的函數即可以接收數組也可以接收字符串。
交叉類型
交叉類型是將多個類型合併爲一個類型,支持所有的類型。交叉類型用&
表示,A & B
表示同時包含 A 和 B 的結果
interface Admin {
id: number,
administrator: string,
timestamp: string
}
interface User {
id: number,
groups: number[],
createLog: (id: number) => void,
timestamp: number
}
let t: Admin & User
t!.administrator // 合法 Admin.administrator: string
t!.groups // 合法 User.groups: number[]
t!.id // 合法 id: number
t!.timestamp // 合法 timestamp: never,never表示不允許被賦值
交叉類型 Admin & User 包含了原類型的所有屬性,但是要注意兩個接口都擁有 id 和 timestamp 屬性,且 id 類型相同,timestamp 類型不同。在此交叉類型中,timestamp 屬性類型衝突,不可被賦值。
一個實際的使用場景,mixins函數
function extend<T, U>(first: T, second: U): T & U {
for(const key in second) {
(first as T & U)[key] = second[key] as any
}
return first as T & U
}
var x = extend({ a: 'hello' }, { b: 42 });
元組類型
元組類型用於約束數組中的子項,使用:[typeofmember1, typeofmember2]
表示
const nameAndNumber: [string, number];
nameAndNumber = ['wmui', 18]
類型別名
類型別名可以讓我們給類型起一個別名,在聯合類型和交叉類型中比較實用,使用type SomeName = someValidTypeAnnotation
來創建
type text = string | { text: string };
type coordinates = [number, number];
type callback = (data: string) => void;