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è)超集错洁,主要提供了類(lèi)型系統(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)大的類(lèi)型系統(tǒng)
類(lèi)型系統(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 程序
編寫(xiě) 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)型注解
接下來(lái)讓我們看看 TypeScript 工具帶來(lái)的高級(jí)功能。 給 person
函數(shù)的參數(shù)添加 :string
類(lèi)型注解澜建,如下:
function greeter (person: string) {
return 'Hello, ' + person
}
let user = 'Yee'
console.log(greeter(user))
TypeScript 里的類(lèi)型注解是一種輕量級(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'.
類(lèi)似地饼灿,嘗試刪除 greeter
調(diào)用的所有參數(shù)。 TypeScript 會(huì)告訴你使用了非期望個(gè)數(shù)的參數(shù)調(diào)用了這個(gè)函數(shù)帝美。 在這兩種情況中,TypeScript提供了靜態(tài)的代碼分析晤硕,它可以分析代碼結(jié)構(gòu)和提供的類(lèi)型注解悼潭。
要注意的是盡管有錯(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è)類(lèi)型內(nèi)部的結(jié)構(gòu)兼容,那么這兩個(gè)類(lèi)型就是兼容的窄绒。 這就允許我們?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)
最后彰导,讓我們使用類(lèi)來(lái)改寫(xiě)這個(gè)例子蛔翅。 TypeScript 支持 JavaScript 的新特性,比如支持基于類(lèi)的面向?qū)ο缶幊獭?/p>
讓我們創(chuàng)建一個(gè) User
類(lèi)位谋,它帶有一個(gè)構(gòu)造函數(shù)和一些公共字段山析。因?yàn)轭?lèi)的字段包含了接口所需要的字段,所以他們能很好的兼容掏父。
還要注意的是笋轨,我在類(lèi)的聲明上會(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 里的類(lèi)只是一個(gè)語(yǔ)法糖,本質(zhì)上還是 JavaScript
函數(shù)的實(shí)現(xiàn)膏燃。
4茂卦、使用webpack打包TS
下載依賴(lài)
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)的類(lèi)型說(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)定義它的類(lèi)型
declare var jQuery: (selector: string) => any;
jQuery('#foo');
declare var 并沒(méi)有真的定義一個(gè)變量,只是定義了全局變量 jQuery 的類(lèi)型聂抢,僅僅會(huì)用于編譯時(shí)的檢查钧嘶,在編譯結(jié)果中會(huì)被刪除。它編譯結(jié)果是:
jQuery('#foo');
一般聲明文件都會(huì)單獨(dú)寫(xiě)成一個(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)做定義好了的類(lèi)型有决。
內(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()