1、初識(shí)TypeScript

TypeScript 的介紹
TypeScript是一種由微軟開(kāi)發(fā)的開(kāi)源、跨平臺(tái)的編程語(yǔ)言。它是JavaScript的超集,最終會(huì)被編譯為JavaScript代碼。
2012年10月,微軟發(fā)布了首個(gè)公開(kāi)版本的TypeScript,2013年6月19日,在經(jīng)歷了一個(gè)預(yù)覽版之后微軟正式發(fā)布了正式版TypeScript
TypeScript的作者是安德斯·海爾斯伯格,C#的首席架構(gòu)師。它是開(kāi)源和跨平臺(tái)的編程語(yǔ)言。
TypeScript擴(kuò)展了JavaScript的語(yǔ)法,所以任何現(xiàn)有的JavaScript程序可以運(yùn)行在TypeScript環(huán)境中。
TypeScript是為大型應(yīng)用的開(kāi)發(fā)而設(shè)計(jì),并且可以編譯為JavaScript。
TypeScript 是 JavaScript 的一個(gè)超集,主要提供了類型系統(tǒng)和對(duì) ES6+ 的支持,它由 Microsoft 開(kāi)發(fā),代碼開(kāi)源于 GitHub上
TypeScript 的特點(diǎn)
TypeScript 主要有 3 大特點(diǎn):
- 始于JavaScript,歸于JavaScript
TypeScript 可以編譯出純凈、 簡(jiǎn)潔的 JavaScript 代碼,并且可以運(yùn)行在任何瀏覽器上、Node.js 環(huán)境中和任何支持 ECMAScript 3(或更高版本)的JavaScript 引擎中。
- 強(qiáng)大的類型系統(tǒng)
類型系統(tǒng)允許 JavaScript 開(kāi)發(fā)者在開(kāi)發(fā) JavaScript 應(yīng)用程序時(shí)使用高效的開(kāi)發(fā)工具和常用操作比如靜態(tài)檢查和代碼重構(gòu)。
- 先進(jìn)的 JavaScript
TypeScript 提供最新的和不斷發(fā)展的 JavaScript 特性,包括那些來(lái)自 2015 年的 ECMAScript 和未來(lái)的提案中的特性,比如異步功能和 Decorators,以幫助建立健壯的組件。
總結(jié)
TypeScript 在社區(qū)的流行度越來(lái)越高,它非常適用于一些大型項(xiàng)目,也非常適用于一些基礎(chǔ)庫(kù),極大地幫助我們提升了開(kāi)發(fā)效率和體驗(yàn)。
2、 安裝 TypeScript
命令行運(yùn)行如下命令,全局安裝 TypeScript:
npm install -g typescript
安裝完成后,在控制臺(tái)運(yùn)行如下命令,檢查安裝是否成功(3.x):
tsc -V
3、第一個(gè) TypeScript 程序
編寫 TS 程序
src/helloworld.ts
function greeter (person) {
return 'Hello, ' + person
}
let user = 'Yee'
console.log(greeter(user))
手動(dòng)編譯代碼
我們使用了.ts擴(kuò)展名,但是這段代碼僅僅是 JavaScript 而已。
在命令行上,運(yùn)行 TypeScript 編譯器:
tsc helloworld.ts
輸出結(jié)果為一個(gè) helloworld.js文件,它包含了和輸入文件中相同的 JavsScript 代碼。
在命令行上,通過(guò) Node.js 運(yùn)行這段代碼:
node helloworld.js
控制臺(tái)輸出:
Hello, Yee
vscode自動(dòng)編譯
1). 生成配置文件tsconfig.json
tsc --init
2). 修改tsconfig.json配置
"outDir": "./js",
"strict": false,
3). 啟動(dòng)監(jiān)視任務(wù):
終端 -> 運(yùn)行任務(wù) -> 監(jiān)視tsconfig.json
類型注解
接下來(lái)讓我們看看 TypeScript 工具帶來(lái)的高級(jí)功能。 給 person函數(shù)的參數(shù)添加 :string 類型注解,如下:
function greeter (person: string) {
return 'Hello, ' + person
}
let user = 'Yee'
console.log(greeter(user))
TypeScript 里的類型注解是一種輕量級(jí)的為函數(shù)或變量添加約束的方式。 在這個(gè)例子里,我們希望 greeter 函數(shù)接收一個(gè)字符串參數(shù)。 然后嘗試把 greeter 的調(diào)用改成傳入一個(gè)數(shù)組:
function greeter (person: string) {
return 'Hello, ' + person
}
let user = [0, 1, 2]
console.log(greeter(user))
重新編譯,你會(huì)看到產(chǎn)生了一個(gè)錯(cuò)誤:
error TS2345: Argument of type 'number[]' is not assignable to parameter of type 'string'.
類似地,嘗試刪除 greeter調(diào)用的所有參數(shù)。 TypeScript 會(huì)告訴你使用了非期望個(gè)數(shù)的參數(shù)調(diào)用了這個(gè)函數(shù)。 在這兩種情況中,TypeScript提供了靜態(tài)的代碼分析,它可以分析代碼結(jié)構(gòu)和提供的類型注解。
要注意的是盡管有錯(cuò)誤,greeter.js 文件還是被創(chuàng)建了。 就算你的代碼里有錯(cuò)誤,你仍然可以使用 TypeScript。但在這種情況下,TypeScript 會(huì)警告你代碼可能不會(huì)按預(yù)期執(zhí)行。
接口
讓我們繼續(xù)擴(kuò)展這個(gè)示例應(yīng)用。這里我們使用接口來(lái)描述一個(gè)擁有 firstName 和 lastName 字段的對(duì)象。 在 TypeScript里,只在兩個(gè)類型內(nèi)部的結(jié)構(gòu)兼容,那么這兩個(gè)類型就是兼容的。 這就允許我們?cè)趯?shí)現(xiàn)接口時(shí)候只要保證包含了接口要求的結(jié)構(gòu)就可以,而不必明確地使用 implements 語(yǔ)句。
interface Person {
firstName: string
lastName: string
}
function greeter (person: Person) {
return 'Hello, ' + person.firstName + ' ' + person.lastName
}
let user = {
firstName: 'Yee',
lastName: 'Huang'
}
console.log(greeter(user))
類
最后,讓我們使用類來(lái)改寫這個(gè)例子。 TypeScript 支持 JavaScript 的新特性,比如支持基于類的面向?qū)ο缶幊獭?/p>
讓我們創(chuàng)建一個(gè) User 類,它帶有一個(gè)構(gòu)造函數(shù)和一些公共字段。因?yàn)轭惖淖侄伟私涌谒枰淖侄?,所以他們能很好的兼容?/p>
還要注意的是,我在類的聲明上會(huì)注明所有的成員變量,這樣比較一目了然。
class User {
fullName: string
firstName: string
lastName: string
constructor (firstName: string, lastName: string) {
this.firstName = firstName
this.lastName = lastName
this.fullName = firstName + ' ' + lastName
}
}
interface Person {
firstName: string
lastName: string
}
function greeter (person: Person) {
return 'Hello, ' + person.firstName + ' ' + person.lastName
}
let user = new User('Yee', 'Huang')
console.log(greeter(user))
重新運(yùn)行 tsc greeter.ts,你會(huì)看到 TypeScript 里的類只是一個(gè)語(yǔ)法糖,本質(zhì)上還是 JavaScript函數(shù)的實(shí)現(xiàn)。
4、使用webpack打包TS
下載依賴
npm install -D typescript
npm install -D webpack webpack-cli
npm install -D webpack-dev-server
npm install -D html-webpack-plugin clean-webpack-plugin
npm install -D ts-loader
npm install -D cross-env
入口JS: src/main.ts
document.write('Hello Webpack TS!')
index頁(yè)面: public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>webpack & TS</title>
</head>
<body>
</body>
</html>
build/webpack.config.js
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')
const isProd = process.env.NODE_ENV === 'production' // 是否生產(chǎn)環(huán)境
function resolve (dir) {
return path.resolve(__dirname, '..', dir)
}
module.exports = {
mode: isProd ? 'production' : 'development',
entry: {
app: './src/main.ts'
},
output: {
path: resolve('dist'),
filename: '[name].[contenthash:8].js'
},
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
include: [resolve('src')]
}
]
},
plugins: [
new CleanWebpackPlugin({
}),
new HtmlWebpackPlugin({
template: './public/index.html'
})
],
resolve: {
extensions: ['.ts', '.tsx', '.js']
},
devtool: isProd ? 'cheap-module-source-map' : 'cheap-module-eval-source-map',
devServer: {
host: 'localhost', // 主機(jī)名
stats: 'errors-only', // 打包日志輸出輸出錯(cuò)誤信息
port: 8081,
open: true
},
}
配置打包命令
"dev": "cross-env NODE_ENV=development webpack-dev-server --config build/webpack.config.js",
"build": "cross-env NODE_ENV=production webpack --config build/webpack.config.js"
運(yùn)行與打包
npm run dev
npm run build
5、其他
聲明文件
當(dāng)使用第三方庫(kù)時(shí),我們需要引用它的聲明文件,才能獲得對(duì)應(yīng)的代碼補(bǔ)全、接口提示等功能
什么是聲明語(yǔ)句
假如我們想使用第三方庫(kù) jQuery,一種常見(jiàn)的方式是在 html 中通過(guò) <script> 標(biāo)簽引入 jQuery,然后就可以使用全局變量 $ 或 jQuery 了。
但是在 ts 中,編譯器并不知道 $ 或 jQuery 是什么東西
/*
當(dāng)使用第三方庫(kù)時(shí),我們需要引用它的聲明文件,才能獲得對(duì)應(yīng)的代碼補(bǔ)全、接口提示等功能。
聲明語(yǔ)句: 如果需要ts對(duì)新的語(yǔ)法進(jìn)行檢查, 需要要加載了對(duì)應(yīng)的類型說(shuō)明代碼
declare var jQuery: (selector: string) => any;
聲明文件: 把聲明語(yǔ)句放到一個(gè)單獨(dú)的文件(jQuery.d.ts)中, ts會(huì)自動(dòng)解析到項(xiàng)目中所有聲明文件
下載聲明文件: npm install @types/jquery --save-dev
*/
jQuery('#foo');
// ERROR: Cannot find name 'jQuery'
這時(shí),我們需要使用 declare var 來(lái)定義它的類型
declare var jQuery: (selector: string) => any;
jQuery('#foo');
declare var 并沒(méi)有真的定義一個(gè)變量,只是定義了全局變量 jQuery 的類型,僅僅會(huì)用于編譯時(shí)的檢查,在編譯結(jié)果中會(huì)被刪除。它編譯結(jié)果是:
jQuery('#foo');
一般聲明文件都會(huì)單獨(dú)寫成一個(gè) xxx.d.ts 文件
創(chuàng)建 01_jQuery.d.ts, 將聲明語(yǔ)句定義其中, TS編譯器會(huì)掃描并加載項(xiàng)目中所有的TS聲明文件
declare var jQuery: (selector: string) => any;
很多的第三方庫(kù)都定義了對(duì)應(yīng)的聲明文件庫(kù), 庫(kù)文件名一般為 @types/xxx, 可以在 https://www.npmjs.com/package/package 進(jìn)行搜索
有的第三庫(kù)在下載時(shí)就會(huì)自動(dòng)下載對(duì)應(yīng)的聲明文件庫(kù)(比如:webpack),有的可能需要單獨(dú)下載(比如jQuery/react)
內(nèi)置對(duì)象
JavaScript 中有很多內(nèi)置對(duì)象,它們可以直接在 TypeScript 中當(dāng)做定義好了的類型。
內(nèi)置對(duì)象是指根據(jù)標(biāo)準(zhǔn)在全局作用域(Global)上存在的對(duì)象。這里的標(biāo)準(zhǔn)是指 ECMAScript 和其他環(huán)境(比如 DOM)的標(biāo)準(zhǔn)。
1.ECMAScript 的內(nèi)置對(duì)象
Boolean
Number
String
Date
RegExp
Error
/* 1. ECMAScript 的內(nèi)置對(duì)象 */
let b: Boolean = new Boolean(1)
let n: Number = new Number(true)
let s: String = new String('abc')
let d: Date = new Date()
let r: RegExp = /^1/
let e: Error = new Error('error message')
b = true
// let bb: boolean = new Boolean(2) // error
2.BOM 和 DOM 的內(nèi)置對(duì)象
Window
Document
HTMLElement
DocumentFragment
Event
NodeList
const div: HTMLElement = document.getElementById('test')
const divs: NodeList = document.querySelectorAll('div')
document.addEventListener('click', (event: MouseEvent) => {
console.dir(event.target)
})
const fragment: DocumentFragment = document.createDocumentFragment()