TypeScript是JavaScript的超集,也就是說TypeScript不只包含了JavaScript的所有內容,同時也包含其餘內容。typescript
TypeScript = JavaScript + 類型系統 + ES6+新特性支持。
TypeScript原始類型能夠和JavaScript基礎類型一一對應。數組
const a: number = 1 // NaN const b: string = 'foo' const c: boolean = true // false const d: void = undefined const e: null = null const f: undefined = undefined const g: symbol = Symbol()
const arr1: Array<number> = [1, 2] const arr2: string[] = ['foo', 'bar']
指的是明確數量和類型的數組。函數
const arr: [number, string] = [1, 'foo'] // 能夠經過如下方式正常獲取數組中的元素 console.log(arr[1]) const [num, str] = arr
const obj: object = {} obj['name'] = 'zhangsan'
枚舉類型指的是經過enum關鍵字定義一組鍵值對數據,數據定義完成後只能讀取,不能修改。post
// 文章狀態 enum PostStatus { // 草稿 Draft = 0, // 未發佈 Unpublished = 1, // 已發佈 Published = 2 } const post = { title: 'typescript', status: PostStatus.Published } // 直接經過enum聲明的枚舉類型能夠用數字獲取枚舉名稱 console.log(PostStatus[0]) // Draft
常量枚舉:在enum關鍵字前面加上constthis
// 文章狀態 const enum PostStatus { // 草稿 Draft = 0, // 未發佈 Unpublished = 1, // 已發佈 Published = 2 } // 此時再用數字獲取枚舉值就會報錯 console.log(PostStatus[0])
never表示永遠不存在值的類型,一般用於老是拋出異常或者永遠不會有返回值的函數的返回值類型。rest
// 拋出異常 function fn(): never { throw new Error() } // 永遠不會有返回值 function fn1(): never { while (true) { } }
// 能夠在聲明函數的時候用註解的方式爲參數和返回值添加類型 function sum(a: number, b: number): number { return a + b } // 也能夠用箭頭函數表示函數類型 const sum1: (a: number, b: number) => number = function (a, b) { return a + b } // 函數聲明後,調用時只能傳入與聲明相對應的參數類型和參數數量 // 或者使用可選參數和剩餘參數 function test(a?: number, ...rest: number[]) { // todo }
在TypeScript中能夠爲同一個函數提供多個函數類型定義來進行函數重載。code
// 重載一 function test(x: number): number; // 重載二 function test(x: string): string; // 並非重載的一部分,只是實現邏輯 function test(x: any): any { if (typeof x === 'number') { return x } else if (typeof x === 'string') { return x } } test(1) test('foo')
ts中可使用any表示任意類型,提供any主要是爲了兼容老的js代碼。對象
let a: any = 1 // 能夠改變a的類型 a = 'foo'
當未改變量指明類型的時候,ts能夠經過參數值推斷參數類型。繼承
// 此時會自動推斷a的類型爲number const a = 1
ts中能夠手動指定變量的類型。索引
const a: number | undefined = undefined // 將a的類型轉爲指定爲number let b: number = a as number let c: number = <number>a
能夠經過interface關鍵字設置對象必須知足某種要求。
const enum PostStatus { // 草稿 Draft = 0, // 未發佈 Unpublished = 1, // 已發佈 Published = 2 } // 要求文章必須具有title,status, id屬性,能夠有subtitle屬性,其中id爲只讀屬性 interface Post { title: string subtitle?: string status: PostStatus, readonly id: number } let obj: Post = { title: 'typescript', status: PostStatus.Draft, id: 1 } // 只讀屬性不能修改 obj.id = 2
針對cache這種屬性不肯定的對象,可使用動態成員。
interface ICache { // 要求屬性和屬性值均爲字符串 [key: string]: string } let cache: ICache = {} // 能夠在使用的時候給對象添加符合要求的屬性 cache['foo'] = 'bar'
TypeScript在ES2015的class類基礎上添加了一些關鍵字,用於描述類的類型。
class Person { name: string // 私有屬性,外部沒法訪, 能夠添加readonly使其變爲只讀屬性 private readonly type: string = 'person' // protected 受保護,只能在內部和子類內部使用 protected field: string = 'foo' constructor(name: string) { this.name = name } sayHi(msg: string) { // 能夠在類內部訪問私有屬性 console.log(`my name is ${this.name}, i am a ${this.type}, ${msg}`) } } class Student extends Person { constructor(name: string) { super(name) } sayHi() { // 能訪問父類受保護的屬性,可是不能訪問私有private屬性 console.log(this.field) } }
當privite用在constructor前面時,那麼這個類就不能在其餘地方使用new生成實例。
class Book { title: string; private constructor(title: string) { this.title = title } // 可經過靜態方法提供實例化對象的途徑 static create(title: string) { return new Book(title) } } const ts = Book.create('TypeScript')
同時,類能夠繼承接口,表示類須要具有某些方法或者屬性。
interface IBook { getContent(): string } // 類能夠繼承多個接口 class Book implements IBook { title: string; constructor(title: string) { this.title = title } // 必須實現接口 getContent(): string { return `TypeScript is a Language` } }
抽象類聲明和普通類類似,只不過抽象類不能實例化,同時抽象類中的抽象方法須要子類實現。
abstract class Person { name: string; // 抽象屬性 abstract field: string constructor(name: string) { this.name = name } // 抽象方法 abstract sayHi(msg: string): void } class Student extends Person { field: string = 'test'; sayHi(msg: string): void { console.log(msg) } }
泛型能夠理解爲將可變化的類型看成一個參數
const createNumberArray = function(length: number, value: number): number[] { return Array(length).fill(value) } const arr = createNumberArray(2, 1) // [1, 1] const createStringArray = function(length: number, value: string): string[] { return Array(length).fill(value) } const arr1 = createStringArray(2, 'foo') // [foo, foo]
在上面的例子中,createNumberArray和createStringArray除了參數和返回值的類型不一樣以外,其他都同樣,此時就可使用範型。
function createArray<T>(length: number, value: T): T[] { return Array(length).fill(value) } // 在使用時指定類型 const arr = createArray<number>(2, 1) // [1, 1] const arr1 = createArray<string>(2, 'foo') // [foo, foo]
interface Person { name: string } // 經過extends爲類型添加約束,要求類型必須實現了Person接口 function intro<T extends Person>(person: T) { return person.name } intro({ name: 'zs' }) // ok intro(5) //error number類型沒有實現Person
interface Person { name: string, age?: number } // 此範型要求T必須實現Person, U必須是T的屬性中的某一個 // keyof是索引類型查詢操做符,假設T是一個類型,那麼keyof T產生的類型是T的屬性名稱字符串字面量類型構成的聯合類型 function intro<T extends Person, U extends keyof T>(person: T, key: U) { return person[key] } intro({ name: 'zs' }, 'name') // 至關於 function intro<T extends Person, U extends 'name' | 'age'>(person: T, key: U) { return person[key] }
class Person { constructor() { } } function create<T>(c: { new(): T; }) { return new c() } const zs = create<Person>(Person)
import { camelCase } from 'lodash' // 當引用相似lodash這種沒有類型聲明文件的第三方庫時,若是不明確聲明引入的變量的類型,將會報錯 declare let camelCase = (str?: string) => string console.log(camelCase('hello typescript'))
一般類型聲明會放入*.d.ts文件中