一、初識 TypeScript
TypeScript 是 JavaScript 的一個超集,主要提供了類型系統和對 ES6 的支持,它由 Microsoft 開發,代碼開源於 GitHub 上。
它的第一個版本發佈於 2012 年 10 月,經歷了多次更新後,現在已成爲前端社區中不可忽視的力量,不僅在 Microsoft 內部得到廣泛運用,而且 Google 開發的 Angular 從 2.0 開始就使用了 TypeScript 作爲開發語言,Vue 3.0 也使用 TypeScript 進行了重構。
TypeScript 是一種由微軟開發的自由和開源的編程語言。它是 JavaScript 的一個超集,而且本質上向這個語言添加了可選的靜態類型和基於類的面向對象編程。
TypeScript 提供最新的和不斷髮展的 JavaScript 特性,包括那些來自 2015 年的 ECMAScript 和未來的提案中的特性,比如異步功能和 Decorators,以幫助建立健壯的組件。
二、環境搭建
全局安裝ts編譯器:
npm install typescript -g
tsc -h // 查看所有命令
tsc -v // 查看版本號
常用命令行語法:tsc [options] [file...]
tsc hello.ts
// 把指令的 .ts 文件編譯成 .js 文件。
tsc ./src/app.ts --outFile ./dist/app.js
自動監聽 ts文件變化並編譯成 js
tsc --rootDir ./src/* --outDir ./dist --watch
生成 ts 項目配置文件 tsconfig.json:
tsc --init
編寫 ts 配置文件,指定 "rootDir": "./src"
和 "outDir": "./dist"
,再次運行:
tsc --watch
三、五分鐘入門 TypeScript
1、類型註解
TypeScript裏的類型註解是一種輕量級的爲函數或變量添加約束的方式。
let name:string = 'Jane'
// string 是 person 函數的參數類型註解
function greet(person:string) {
return 'hello, '+person
}
greet('Jane')
greet(name)
// Argument of type 'number' is not assignable to parameter of type 'string'.
greet(20)
// Expected 1 arguments, but got 0.
greet()
當你的 .ts 代碼裏有錯誤,你仍然可以使用TypeScript,仍然可以順利地被編譯成 .js 文件。但在這種情況下,TypeScript 會警告你代碼可能不會按預期執行。
2、接口
在TypeScript裏,只在兩個類型內部的結構兼容那麼這兩個類型就是兼容的。 這就允許我們在實現接口時候只要保證包含了接口要求的結構就可以,而不必明確地使用 implements語句。
// 定義一個接口
interface Person {
firstName: string,
lastName: string
}
function greet(p:Person) {
return `hello ${p.firstName} ${p.lastName}`
}
// 測試一下
let user = { firstName:'zhang', lastName:'san' }
greet(user)
3、類
TypeScript支持JavaScript的新特性,比如支持基於類的面向對象編程。讓我們創建一個Student類,它帶有一個構造函數和一些公共字段。 注意類和接口可以一起工作。
// 類
class Student {
public fullName = ''
constructor(public firstName, public lastName) {
this.fullName = `${firstName} ${lastName}`
}
}
// 接口
interface Person {
firstName: string,
lastName: string
}
// 類型註解
function greet(p:Person) {
return `hello ${p.firstName} ${p.lastName}`
}
// 測試一下
let user = new Student('zhang', 'san')
greet(user)
四、基本數據類型
TypeScript支持與JavaScript幾乎相同的數據類型,此外還提供了實用的元組、枚舉、any 和 void 等。
1、布爾、數字、字符串
// 布爾類型
let isBol: boolean = false
// 數字類型
let age: number = 20
// 字符串類型
let myname: string = 'zhangsan'
myname = "li si"
let msg = `${myname}'s age is ${age}`
2、數組、元組
// 數組(type[] 或 Array<type>)
let arr1: number[] = [1,2,3]
let arr2: string[] = ['1','2','3']
let arr3: Array<number> = [4,5,6]
let arr4: Array<string[]> = [['1','2'],['3','4']]
// 元組
// 元組類型允許表示一個已知元素數量和類型的數組,各元素的類型不必相同。當訪問一個越界的元組元素時,會出現錯誤。
let x: [string, number, boolean] = ['hello', 30, true]
console.log(x[0],x[1],x[2])
// x[3] = 'world' // 報錯
3、枚舉類型
// 枚舉
enum Cate {
office = '辦公用品',
car = '汽車生活',
clothe = '男裝女裝',
sport = '戶外運動',
book = '圖書音像'
}
let office_zh1 = Cate.office
console.log('enum', Cate)
4、any類型、void類型
// any類型
let noSure: any = 23.9
noSure = 'hello any'
noSure = [1,2,3]
// let noSureArr: Array<any> = ['hello', false, 23]
let noSureArr: any[] = ['hello', false, 23]
// void類型,與any類型相反,它表示沒有任何類型。
// 聲明一個void類型的變量沒有什麼大用,因爲你只能爲它賦予undefined和null
let v1: void = undefined
let v2: void = null
// 當一個函數沒有返回值時,你通常會見到其返回值類型是 void
function foo(arg:any): void {
console.log('該函數的返回值類型爲void')
}
五、函數
1、函數聲明
// 一個函數有輸入和輸出,要在 TypeScript 中對其進行約束
function sum(x: number, y: number): number {
return x + y
}
sum(1,2)
// 輸入多餘的(或者少於要求的)參數,是不被允許的
// sum(1)
// sum(1,2,3)
2、函數表達式
let sub = function(x: number, y: number): number {
return x - y
}
sub(10,5)
// 還可以使用接口的方式來定義一個函數需要符合的形狀
interface SearchFunc {
(source: string, subStr: string): boolean
}
let search: SearchFunc = function(source: string, subStr: string) {
return source.search(subStr) !== -1
}
3、可選參數
// 用 ? 表示可選的參數,可選參數必須接在必需參數後面,可選參數後面不允許再出現必需參數了。
function foo(a: string, b?:string): string {
if(b) return a+b
return a
}
foo('hello')
foo('hello','world')
4、參數默認值
// TypeScript 會將添加了默認值的參數識別爲可選參數
// 此時,可選參數不必一定要在必需參數後面
function bar(a:string='hello', b:string) {
return a +b
}
bar(undefined,'world')
bar('hi', 'lisi')
5、剩餘參數
// 函數剩餘參數可以使用 ...rest 的方式獲取函數中的剩餘參數(rest 參數)
function push(arr:any[], ...rest:any[]): any[] {
return [...arr, ...rest]
}
push([0], 1,2,3,4)
6、函數重載
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,前幾次都是函數定義,最後一次是函數實現。
// TypeScript 會優先從最前面的函數定義開始匹配,所以多個函數定義如果有包含關係,需要優先把精確的定義寫在前面。
reverse(100)
reverse('hello')
六、接口
什麼是接口? 在面嚮對象語言中,接口(Interfaces)是一個很重要的概念,它是對行爲的抽象,而具體如何行動需要由類(classes)去實現(implement)。 TypeScript 中的接口是一個非常靈活的概念,除了可用於對類的一部分行爲進行抽象以外,也常用於對「對象的形狀(Shape)」進行描述。
在 TypeScript 中,我們使用接口(Interfaces)來定義對象的類型,如下示例:
interface Person {
name: string, // 必須屬性
age: number, // 必須屬性
mobile?: string, // 可選屬性
[propName: string]: any, // 任意屬性
readonly role: number, // 只讀屬性
}
// 賦值的時候,變量的形狀必須和接口的形狀保持一致
let tom: Person = {
name: 'tom',
age: 30,
mobile: '110',
gender: 'male',
role: 1
}
- 注意1:使用 [propName: string] 定義了任意屬性取 string 類型的值。一旦定義了任意屬性,那麼確定屬性和可選屬性的類型都必須是它的類型的子集。
- 注意2:只讀的約束存在於第一次給對象賦值的時候,而不是第一次給只讀屬性賦值的時候。
七、泛型
泛型(Generics)是指在定義函數、接口或類的時候,不預先指定具體的類型,而在使用的時候再指定類型的一種特性。
function print<T>(arg: T): void {
console.log('arg', arg)
}
print<string>('hello')
print<number>(100)
print<any>(1.2345)
function add<T>(x: T, y: T, z: T): void {
console.log(x, y, z)
}
add<number>(1,2,3)
add<string>('a','b','c')
add<any>('a',20,'c')
1、支持使用多個泛型
function swap<T,U>(tup:[T,U]): [U,T] {
return [tup[1], tup[0]]
}
swap<number, string>([100, 'hello']) // ['hello', 100]
interface MyU { a: string; b: number }
swap<boolean, MyU>([true, {a:'hi',b:11}]) // [{a:'hi',b:11}, true]
2、泛型約束
interface LengthType {
length: number
}
function printLength<T extends LengthType>(arg: T): number {
// 爲什麼要進行泛型約束呢?因爲入參的數據類型不確定,它可能沒有length屬性
return arg.length
}
printLength<string>('hello') // 5
printLength<Array<any>>([1,2,'a','b']) // 4
3、泛型類
class Dog<T> {
name: T
constructor(name: T) {
this.name = name
}
sayHi(): T {
return this.name
}
}
const dog = new Dog<string>('dahuang') // 調用constructor()
dog.sayHi()
4、泛型接口(泛型類型)
interface Tfn1<T> {
(x: T, y: T, z: T): T
}
const tf1: Tfn1<number> = function(x: number, y: number, z: number): number {
return x * y * z
}
tf1(1,2,3)
const tf3: Tfn1<string> = function(x: string, y: string, z: string): string {
return x + y + z
}
tf3('a','b','c')
interface Tfn2 {
<T>(x: T, y: T, z: T): void
}
const tf2: Tfn2 = <T>(x:T, y:T, z: T): void => {
console.log(x, y, z)
}
// const tf2: Tfn2 = function <T>(x:T, y:T, z: T):void {
// console.log(x, y, z)
// }
tf2<string>('a','b','c')
tf2<number>(10, 20, 30)
本篇結束,感謝關注!!!