Vue3.0底層都要用ts重寫了,相信未來能用javascript寫的都用typescript寫了
配置准備
node的安裝就不說了,這個必須有。
配置淘寶源,或者安裝nrm,來方便切換npm源的版本(推薦后者)
npm config set registry https://registry.npm.taobao.org/
安裝
npm install typescript@2.9.2 -g
npm install ts-node@7.0.0 -g // 讓node支持ts
運行
兩種方式快速運行ts代碼
-
安裝ts-node,直接在命令行環境下敲ts代碼,和node運行環境類似;
-
創建一個目錄 >>> 創建
.vscode
目錄 >>> 創建launch.json
文件,在文件內這么寫:{ "configurations": [ { "name": "ts-node", "type": "node", "request": "launch", "program": "注意看這里,要寫成ts-node對應的可執行文件,Windows 用戶注意了,你應該寫成 ${workspaceRoot}/node_modules/ts-node/dist/bin.js", "args": ["${relativeFile}"], "cwd": "${workspaceRoot}", "protocol": "inspector" } ] }
然后找到該目錄下你新建的文件,找到vscode的調試選項,選擇ts-node,然后點擊調試,你就可以在控制台看到結果了!
配置文件
在終端中輸入tsc --init:它是一個TypeScript項目的配置文件,可以通過讀取它來設置TypeScript編譯器的編譯參數
{
"compilerOptions": {
/* 基本選項 */
"target": "es5", // 指定 ECMAScript 目標版本: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'
"module": "commonjs", // 指定使用模塊: 'commonjs', 'amd', 'system', 'umd' or 'es2015'
"lib": [], // 指定要包含在編譯中的庫文件
"allowJs": true, // 允許編譯 javascript 文件
"checkJs": true, // 報告 javascript 文件中的錯誤
"jsx": "preserve", // 指定 jsx 代碼的生成: 'preserve', 'react-native', or 'react'
"declaration": true, // 生成相應的 '.d.ts' 文件
"sourceMap": true, // 生成相應的 '.map' 文件
"outFile": "./", // 將輸出文件合並為一個文件
"outDir": "./", // 指定輸出目錄
"rootDir": "./", // 用來控制輸出目錄結構 --outDir.
"removeComments": true, // 刪除編譯后的所有的注釋
"noEmit": true, // 不生成輸出文件
"importHelpers": true, // 從 tslib 導入輔助工具函數
"isolatedModules": true, // 將每個文件做為單獨的模塊 (與 'ts.transpileModule' 類似).
/* 嚴格的類型檢查選項 */
"strict": true, // 啟用所有嚴格類型檢查選項
"noImplicitAny": true, // 在表達式和聲明上有隱含的 any類型時報錯
"strictNullChecks": true, // 啟用嚴格的 null 檢查
"noImplicitThis": true, // 當 this 表達式值為 any 類型的時候,生成一個錯誤
"alwaysStrict": true, // 以嚴格模式檢查每個模塊,並在每個文件里加入 'use strict'
/* 額外的檢查 */
"noUnusedLocals": true, // 有未使用的變量時,拋出錯誤
"noUnusedParameters": true, // 有未使用的參數時,拋出錯誤
"noImplicitReturns": true, // 並不是所有函數里的代碼都有返回值時,拋出錯誤
"noFallthroughCasesInSwitch": true, // 報告switch語句的fallthrough錯誤。(即,不允許switch的case語句貫穿)
/* 模塊解析選項 */
"moduleResolution": "node", // 選擇模塊解析策略: 'node' (Node.js) or 'classic' (TypeScript pre-1.6)
"baseUrl": "./", // 用於解析非相對模塊名稱的基目錄
"paths": {}, // 模塊名到基於 baseUrl 的路徑映射的列表
"rootDirs": [], // 根文件夾列表,其組合內容表示項目運行時的結構內容
"typeRoots": [], // 包含類型聲明的文件列表
"types": [], // 需要包含的類型聲明文件名列表
"allowSyntheticDefaultImports": true, // 允許從沒有設置默認導出的模塊中默認導入。
/* Source Map Options */
"sourceRoot": "./", // 指定調試器應該找到 TypeScript 文件而不是源文件的位置
"mapRoot": "./", // 指定調試器應該找到映射文件而不是生成文件的位置
"inlineSourceMap": true, // 生成單個 soucemaps 文件,而不是將 sourcemaps 生成不同的文件
"inlineSources": true, // 將代碼與 sourcemaps 生成到一個文件中,要求同時設置了 --inlineSourceMap 或 --sourceMap 屬性
/* 其他選項 */
"experimentalDecorators": true, // 啟用裝飾器
"emitDecoratorMetadata": true // 為裝飾器提供元數據的支持
}
}
還可以指定不要被編譯的文件
{
"files": [
"./some/file.ts"
]
}
可以使用 include 和 exclude 選項來指定需要包含的文件,和排除的文件
{
"include": [
"./folder"
],
"exclude": [
"./folder/**/*.spec.ts",
"./folder/someSubFolder"
]
}
簡單的命令行程序
技巧
文件首行寫#!/usr/bin/env ts-node
的作用?
- 此為shebang,說明該腳本用什么語言解析,並利用env查找該在哪查找該語言
給文件添加執行權限
// 添加可執行權限(windows用戶不需要)
chmod +x 1.ts
// 添加執行權限后可以直接執行文件,如下
./1.ts
這樣,我們就可以通過給cmd.ts文件中打印process.argv,來獲取到命令行參數了!
┌─(~/TypeScript/tsdemo)────────────────────────────────────────────(gaohang@isaacgao:s005)─┐ ────────────────────────────────────────(gaohang@isaacgao:s005)─┐
└─(22:59:03)──> ./cmd.ts haha xixi ──(Sun,Jun30)─┘ ──(Sat,Jun29)─┘
hello world 'string'.
[ 'node',
'/Users/gaohang/TypeScript/tsdemo/cmd.ts',
'haha',
'xixi' ]
┌─(~/TypeScript/tsdemo)────────────────────────────────────────────(gaohang@isaacgao:s005)─┐ ────────────────────────────────────────(gaohang@isaacgao:s005)─┐
└─(23:05:23)──>
新建add.ts,執行
#!/usr/bin/env ts-nod
let a: number = process.argv[2];
let b: number = process.argv[3];
console.log(a + b);
//執行 ./add.ts 1 2
如上,我們執行./add.ts 1 2
后,得到12,並不是預想中的3。可想而知,這里的a,b是字符串類型相加了把。當我們用typescript給a,b規范類型為number后,vscode立即出現紅色下划線:[ts] Type 'string' is not assignable to type 'number'.
這就是typescript的厲害之處,在代碼非運行時就告知我們類型錯誤!
進一步,vscode提供了一處便利,按住cmd同時光標指向process.argv
就可以定位到index.d.ts中全局process的源代碼
interface Process extends EventEmitter {
stdout: WriteStream;
stderr: WriteStream;
stdin: ReadStream;
openStdin(): Socket;
argv: string[];
argv0: string;
execArgv: string[];
execPath: string;
abort(): void;
......
注意到上面,argv是字符串類型的數組,這也解釋了為什么上面process.argv[2]
返回的是字符串,並且規范為number后還是報錯了。
下面我們繼續迭代一下add.ts
#!/usr/bin/env ts-node
let a: number = parseInt(process.argv[2]);
let b: number = parseInt(process.argv[3]);
if (Number.isNaN(a) || Number.isNaN(b)) {
console.warn('對不起哦,你的輸入錯誤了');
process.exit(0)
}
console.log(a + b);
注意,不執行下面,退出進程可以使用process.exit(0)
,一般程序約定,exit(0)是正常退出(即返回0),其余數據是異常退出,不同編號可以對應不同錯誤類型。
執行后竟然報錯了,摘取的關鍵信息如下:
TSError: ⨯ Unable to compile TypeScript:
add.ts(5,12): error TS2339: Property 'isNaN' does not exist on type 'NumberConstructor'.
add.ts(5,31): error TS2339: Property 'isNaN' does not exist on type 'NumberConstructor'.
通過谷歌,你會發現問題出在當前使用版本的api在ts中並不支持!解決方法是在根目錄新建配置tsconfig.json
{
"compilerOptions": {
"lib": [
"es2015"
]
}
}
技巧
函數無返回值可以顯式的聲明: void{}
⚠️可選參數:參數后面加問號,function xxx(n? :number): void {......}
如果覺得代碼很亂,需要優化,就使用提取函數法,把功能提取成一個函數。
if (!n) {
n = 1
}
// 優化為
n = n || 1
interface:接口,聲明后必須完全符合接口的寫法,才不會報錯,可以多,但是不能少!
public:類里面寫public + 參數代表student有三個屬性,相當於把變量聲明和賦值(this.name = name)給精簡了;
函數:參數和返回值都可以規定類型
家譜命令行程序
下面通過一個簡單的命令行打印家譜的程序來進一步理解typescript類型的基本使用。
function createTabs(n: number): string {
return '----'.repeat(n);
}
class Person {
public children: Person[] = []
constructor(public name: string) {}
addChild(child: Person): void {
this.children.push(child)
}
introduceFamily(n?: number): void {
n = n || 0;
// 打印族譜
console.log(`${createTabs(n)}${this.name}`)
this.children.forEach((child) => {
child.introduceFamily(n + 1)
})
}
}
const grandFather = new Person('王爺爺')
const child1 = new Person('王爸爸')
const child2 = new Person('王舅舅')
const child11 = new Person('王爸爸大兒子')
const child12 = new Person('王爸爸二兒子')
const child21 = new Person('王舅舅大兒子')
const child22 = new Person('王舅舅二兒子')
const child23 = new Person('王舅舅三兒子')
const child221 = new Person('王舅舅二兒子的女兒')
grandFather.addChild(child1)
grandFather.addChild(child2)
child2.addChild(child21)
child2.addChild(child22)
child2.addChild(child23)
child1.addChild(child11)
child1.addChild(child12)
child22.addChild(child221)
grandFather.introduceFamily()
// 返回如下
王爺爺
----王爸爸
--------王爸爸大兒子
--------王爸爸二兒子
----王舅舅
--------王舅舅大兒子
--------王舅舅二兒子
------------王舅舅二兒子的女兒
--------王舅舅三兒子