TypeScript概述
TypeScript是JavaScript的一個超集,支持ECMAScript 6 ES6標(biāo)準(zhǔn),TypeScript設(shè)計目標(biāo)是開發(fā)大型應(yīng)用,它可以編譯成純Javascript,編譯出來的Javascript可以運行在任何瀏覽器上。
TypeScript特性。
TypeScript是一種給JavaScript添加特性的語言擴展,增加一下功能,類型批注和編譯時類型檢查,類型推斷,類型擦除,接口,枚舉,Mixin,泛型編程,名字空間,元組,Await,和沖ECMA2015移植過來的,類,模塊,lambda函數(shù)的箭頭語法,可選參數(shù)以及默認參數(shù)。
Javascript與TypeScript的區(qū)別
TypeScript是Javascript的超集,擴展了JavaScript的語法,因此現(xiàn)有的Javascript代碼可以與TypeScript一起工作無需任何更改,TypeScript通過類型注解提供編譯時靜態(tài)類型檢查,TypeScript可處理已有的JavaScript代碼,并只對其中的TypeScript代碼進行編譯。
TypeScript安裝及其環(huán)境搭建
下載Node.js 并 安裝Node.js
【下載NodeJS】
一直”next“
一直"next"
選擇安裝路徑
搭建完成~使用全局安裝typeScript
安裝完成以后,接著輸入命令
查看typescript編譯器的版本信息,代表安裝成功創(chuàng)建一個ts文件并運行
nodePad++ 安裝包
鏈接: https://pan.baidu.com/s/1YTb2NNK7HQ6YELlIxms0mg?pwd=3s8v 提取碼: 3s8v
復(fù)制這段內(nèi)容后打開百度網(wǎng)盤手機App,操作更方便哦
使用tsc new.ts 生成一個.js文件
使用 node new.ts 運行ts文件
TypeScript類型聲明
強類型定義語言在數(shù)度上可能略遜色于弱類型定義語言,但是強類型定義語言帶來的嚴謹性能夠有效的避免許多錯誤。
單個聲明類型、多個類型聲明
//單個聲明類型 var [變量名] : [類型]; var a: let a:number;//多個類型聲明 var [變量名]:[類型1]|[類型2] let c:boolean|string; c = true c = "hello"
任意類型聲明
//任意類型,如果不指定類型,則ts解析器會自動判斷變量的類型為any(隱式的any) //方式一、var [變量名] = 值; //方式二、let [變量名] :[any] let d:any; //任何類型 d = 1; d = "1" d = true;
函數(shù)類型聲明
// 函數(shù)類型 function sum(a:number,b:number):number{ //a,b只能是number類型,返回類型必須是number } function sum(a:number,b:number):number:boolen{ //返回值類型可以說number或者boolen } //沒有返回值函數(shù) function fun():void{ /* * viod 標(biāo)識空,沒有返回值,如果寫return 會報錯 * 可以返回null,undefined */ } // 永遠都不會返回結(jié)果 function fun():never{ throw new Error("error") //never表示永遠不會返回結(jié)果,會報錯 } //設(shè)置函數(shù)結(jié)構(gòu)的類型聲明 希望d是函數(shù),a,b是number,返回類型number let d:(a:number,b:number)=>number d = function(a:number,b:number):number{ return a + b }
unknown類型【未知類型】
//unknown類型,unknow類型變量不能隨便賦值給其他變量, let e:unknown e=10; e="hellow"; e=true; let a:string; a=e; //unknow類型,賦值給其它會報錯 //如果真的想賦值,可以通過如下方式 if(typeof(e)==="string"){ a = e } //或者通過類型斷言:高數(shù)解析器變量的實際類型,跳過報錯 a = e as string a = <string>e
對象類型聲明
// {}用來指定對象中可以包含哪些屬性 let b:{ name:string, age?:number //加一個問好代表這個屬性可有可無,可選屬性 } b = {name:"張三",age:18} b = {name:"張三"} // name必填,[prop:string]:any 任意類型的屬性 let c:{name:string,[prop:string]:any} c = {name:"李四",a:1,b:2,c:"aaaa"};
數(shù)組類型聲明
//格式 // Array<類型> // string[]表示字符串?dāng)?shù)組 let arr:string[]; arr = ['a','b','c'] //數(shù)值類型 let arr2:Array<number> arr2 = [1,2,3]
元組
元組,元素就是固定長度的數(shù)組 語法: [類型,類型,類型] let h : [string,string] h = ["1","2"]
枚舉
//所有可能情況列舉出來 enum Gender{ Male = 0, Fenake = 1 } let i : {name:string,gender:Gender} i={ name:"孫悟空", gender:Gender.male } console.log(i.gender === Gender.Male) // &表示同時滿足類型 let j : {name:string} & {age:number} //類型別名 簡化類型的使用 type myType = 1|2|3|4|5; let k : myType; let l : myType; let m : myType;
TypeScript編譯選項
自動編譯文件
編譯文件時,使用-w指令后,ts編譯器會自動監(jiān)視文件的變化,并在文件發(fā)生變化的時候?qū)ξ募M行重新編輯。
tsc xxx.ts -w
自動編譯整個項目
tsc
但是,使用tsc的前提,是要在項目根目錄下創(chuàng)建一個ts的配置文件 tsconfig.json,添加完成后,只需要tsc命令就可以對整個項目的ts文件進行編譯。
tsconfig.json是ts編譯器的配置文件,可以根據(jù)他的信息可以對代碼進行編譯。配置如下
1. “include”:用來指定哪些ts文件需要編譯
** 表示任意目錄
* 表示任意文件
例如:“include”:[“./src/**/*”]
2. “exclude” 不需要被編譯的文件目錄例如:“exclude”:[".src/hello/**/“]
3.“extends” 繼承 其他的配置文件
*例如:“extends”:”./config/base"
4.“files” 用來指定被編譯的文件的列表,只需要編譯的文件少時才會用到。
“files”:[
“code.te”,
“hellow.ts”,
“binder.ts”
]
5.“compilerOptions” 編譯選項是配置文件中非常重要也比較復(fù)雜的配置選項,在compilerOptions中包含了許多哥子選項,用來完成對編譯器的配置。
“compilerOptions”:{
“target”:“ES6”, //通設(shè)定ts被編譯的ES的版本
“module”:“commonjs”, //指定要使用的模塊化的規(guī)范
“l(fā)ib”:[“dom”], //用來指定項目中的要使用的庫
“outDir”:“./dist”, //用來指定編譯后文件所在的目錄
“outFile”:“./dist/app.js”, //將代碼合并成一個文件,設(shè)置outFile后,所有的全局作用域中的代碼會合并到同一個文件中
“allowJs”:false, //是否對JS文件進行編譯,默認是false
“checkJs”:false, //是否檢查JS代碼符合語法的規(guī)范,默認是false
“removeComments”:true, //編譯時候是否移除注釋
“noEmit”:false, //不生成編譯后的文件
“noEmitError”:true, //當(dāng)有錯誤時候不生成編譯后的文件
“alwaysStrict”:false, //用來設(shè)置編譯后的文件是否使用嚴格模式,默認false
“noImplicitAny”:false //不允許隱式的數(shù)據(jù)類型
}
添加tsconfig.json文件
可以使用tsc或者tsc -w進行運行,生成js文件,
WebPack打包TS代碼
首先下載依賴,在集成終端打開后:
npm init -y tsc --init 產(chǎn)生對應(yīng)的ts.config.js文件 npm install -D typescript npm install -D webpack@4.41.5 webpack-cli@3.3.10 npm install -D webpack-dev-server@3.10.2 啟動開發(fā)服務(wù)器的 npm install -D html-webpack-plugin@4.0.0-alpha clean-webpack-plugin 對html內(nèi)容進行打包 / 清除之前打包好的js文件 npm install -D ts-loader@8.0.11 針對ts文件進行編譯處理 npm install -D cross-env 涉及跨平臺命令
配置打包命令:
"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"
創(chuàng)建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', //模式:生產(chǎn)模式還是開發(fā)模式 entry: { app: './src/main.ts' //程序主入口目錄 }, output: { path: resolve('dist'), //將打包好的文件放到dist目錄里面 filename: '[name].[contenthash:8].js' //產(chǎn)生的js文件是以app加上8位的哈希值.js來命名的 }, module: { rules: [ //rules主要是通過ts-loader這個包針對于ts文件,針對src目錄里面的ts和tsx文件進行編譯處理操作 { test: /\.tsx?$/, use: 'ts-loader', include: [resolve('src')] } ] }, plugins: [ new CleanWebpackPlugin({ //會將dist目錄中以前打包的js文件進行清楚 }), new HtmlWebpackPlugin({ //針對于./public/index.html進行打包的 template: './public/index.html' }) ], resolve: { extensions: ['.ts', '.tsx', '.js'] //針對于'.ts', '.tsx', '.js'這三種文件進行處理引入文件可以不寫他的擴展名 }, //針對于代碼的錯誤提示 devtool: isProd ? 'cheap-module-source-map' : 'cheap-module-eval-source-map', devServer: { host: 'localhost', // 主機名 stats: 'errors-only', // 打包日志輸出輸出錯誤信息 port: 8081, //端口 open: true //自定打開瀏覽器 }, }
最后創(chuàng)建src目錄下的main.ts:
document.write('Hello Webpack TS!') npm run dev后在主頁面中成功查看hellowebpackTS就說明成功運行
TS面向?qū)ο?/h3>定義類
class 類名 {
屬性名: 類型;
constructor(參數(shù): 類型){
this.屬性名 = 參數(shù);
}
方法名(){
....
}}
定義類
修飾符
static 靜態(tài)屬性,通過類即可直接使用,不能被子類共享
readonly 只讀屬性無法修改
public 默認值,可以在類、子類和對象中修改
protected 可以在類、子類中修改
private 可以在類中修改
constructor(public name: string, public age: number) {} 可以直接將屬性定義在構(gòu)造函數(shù)中: //語法糖: name: string; age: number constructor(name: string, age: number) { this.name = name; this.age = age; } //Singleton 類 class Order { count: number = 0 private static instanceRef: Order private constructor() { } static getInstance(): Order { if (Order.instanceRef === undefined) Order.instanceRef = new Order() return Order.instanceRef } } // const order = new Order() => 構(gòu)造函數(shù)是私有的,僅可在類聲明中訪問。 const order1 = Order.getInstance() const order2 = Order.getInstance() order1.count++; order2.count++; console.log(order1.count) //2 console.log(order2.count) //2//---------------------------------- Order有一個private構(gòu)造函數(shù),不能用new實例化 Order,在 static getInstance()中完成調(diào)用該類構(gòu)造函數(shù), 這是調(diào)用該方法的唯一途徑,兩次 console.log 都是打印 2,因為只有一個 Order 的實例。 若想創(chuàng)建一個自身不能被實例化而子類能被實例化的類時,可以用 protected 修飾構(gòu)造函數(shù)。 class OrderItem extends Order { pid: string constructor(pid: string, count: number) { super() this.productid = productid } }
方法重載
聲明多個同名的方法,但只能統(tǒng)一實現(xiàn),結(jié)合條件判斷,使用 | 表明多個類型的返回值。若聲明方法的代碼去掉,代碼仍然正常運行,或者干脆設(shè)置不同的方法名。
重載目的:提供從參數(shù)類型到返回值類型的合適的映射。
應(yīng)用場景:重載構(gòu)造函數(shù)。
重構(gòu)構(gòu)造函數(shù) < = > 用接口表示可能的參數(shù) obj,constructor(properties?: 接口名){}
class Product { getProducts(): void getProducts(id: number): void getProducts(id?: number): void { if (typeof id == 'number'){ console.log(`Getting the product info for ${id}`) }else { console.log('Getting all products') } }}
運行效果:
抽象類
抽象類是專門用來被其他類所繼承的類,它只能被其他類所繼承不能用來創(chuàng)建實例。
抽象方法,抽象方法沒有方法體只能定義在抽象類中,繼承抽象類時抽象方法必須要實現(xiàn)
abstract class Animal{ abstract run(): void; bark(){ console.log('動物在叫~'); }}class Dog extends Animals{ run(){ console.log('狗在跑~'); }}
接口
再JS中并沒有接口概念,接口interface通俗的來說就是對類中的屬性和方法進行統(tǒng)一的類型聲明,哪個類調(diào)用此接口,在一般情況下具有接口中相應(yīng)的類型聲明的屬性和方法,接口中的屬性和方法名后添加表示屬性或方法是可選項,調(diào)用接口的類中可以根據(jù)具體的需要進行聲明,一個類可以實現(xiàn)多個接口的調(diào)用,不同的接口用逗號隔開,需要注意的是,接口中聲明的方法默認是抽象方法,也就是不具備方法體,需要我們調(diào)用接口的時候進行方法重寫。
type myType = { name: string, age: number }; const obj: myType = { name: 'sss', age: 111 };
Interface myInterface { name: string; age: number; } const obj: myInterface = { name: 'sss', age: 111 };
上面代碼中,進行了type和interface的比較
不能創(chuàng)建多個同名type,但是可以創(chuàng)建多個同名接口,采取合并策略。
接口用來定義一個類的結(jié)構(gòu),該類應(yīng)該包含的屬性/方法(不能同時),也可以當(dāng)成類型聲明。
接口只定義對象的結(jié)構(gòu),不考慮實際值。
在接口中,所有的屬性都不賦實際值,所有的方法都是抽象方法。
不能在聯(lián)合或交叉中使用接口類。
interface Person { age: number } interface Customer { n ame: string } type cust = Person | Customer √ interface cust = Person | Customer ×
接口實現(xiàn)
一個類可以實現(xiàn)多個接口,用逗號隔開
class MyClass implements myInter{ constructor(public name: string) { this.name = name; } sayHello(){ console.log('大家好~~'); } }
擴展接口
interface B extends A{ 聲明 B 新增的方法 }
getter 和 setter
在類中定義一組讀取 getter、設(shè)置屬性 setter 的方法,被稱為屬性的存取器。
private _name: string; private _age: number; constructor(name:string, age: number) { this._name = name; this._age = age; } get name(){ return this._name; } set name(value: string){ this._name = value; } get age(){ return this._age; } set age(value: number){ if(value >= 0){ this._age = value } }
此時可以修改 per.name = ‘豬八戒’; per.age = -33;否則若為定義存取器,會報錯。
泛型
(1),繁星差異:當(dāng)x類可用,就可使用與X類兼容的其他對象或子類,即泛型差異適用于結(jié)構(gòu)相同的對象。
(2),不指定泛型,TS可以自動對類型進行推斷。function fn<T>(a: T): T{ //=> 箭頭函數(shù):const fn = <T>(a: T):T =>{……} return a; } fn('huahua') //自動識別為string
(3),泛型可以同時指定多個,一般 T 表示類型,K 表示鍵,V 表示值。
function fn2<T, K>(a: T, b: K):T{ console.log(b); return a;}fn2<number, string>(123, 'hello');
(4),T extends Inter 表示泛型 T 必須是 Inter 實現(xiàn)類(子類)
interface Inter{ length: number } function fn3<T extends Inter>(a: T): number{ return a.length; }
(5),類和接口中同樣可以使用泛型
? 調(diào)用使用泛型的類或接口時,必須指定類型,若不確定類型 →
? Solve:any 類型,extends A 或 > 聲明默認參數(shù)類型 class A <T = any> 啞元類型,class A < T= {}>
? 實例——接口用于比較矩形大小和員工工資。
實例——接口用于比較矩形大小和員工工資。
interface Comparator<T> { compareTo(value: T): number; } class Rt implements Comparator<Rt>{ constructor( private width: number, private height: number){} compareTo(value: Rt): number { return this.width * this.height - value.width * value.height } } class Pg implements Comparator<Pg>{ constructor( public name: string, private salary: number) {} compareTo(value: Pg): number { return this.salary - value.salary; } } const rect1: Rect = new Rect(2, 5); const rect2: Rect = new Rect(2, 3); rect1.compareTo(rect2)>0?console.log("rect1 is bigger"):(rect1.compareTo(rect2)== 0 ? console.log("rects are equal") :console.log("rect1 is smaller")) const prog1: Pg = new Pg("John", 20000); const prog2: Pg = new Pg("Alex", 30000); prog1.compareTo(prog2) > 0 ?console.log(`${prog1.name} is richer`) :prog1.compareTo(prog2) == 0 ? console.log(`earn the same amounts`) : console.log(`${prog1.name} is poorer`)
類裝飾器
(1) 參數(shù)——類的構(gòu)造函數(shù)
(2) 類裝飾器返回類型為 void,不會替換類聲明(觀察類)。返回新函數(shù),會修改構(gòu)造函數(shù)。
Eg:觀察類 function whoAmI (target: Function): void{ console.log(`You are: ${target} `) } @whoAmI class Friend { constructor(private name: string, private age: number){} }
觀察類 2 function UIcomponent (html: string): Funcion { console.log(`The decorator received ${html} \n`); return function(target: Function) { console.log(`A UI component from \n ${target}`) } } @UIcomponent('<h1>Hello Shopper!</h1>') class Shopper { constructor(private name: string) {} }
(3)修改類聲明的裝飾器:
// 使用類型 any[]的 rest 參數(shù),可以混合其他有構(gòu)造函數(shù)的類type constructorMixin = { new(...args: any[]): {} };function useSalutation(salutation: string) { return function <T extends constructorMixin>(target: T) { return class extends target { name: string private message = 'Hello ' + salutation + this.name sayHello() { console.log(`${this.message}`); } } }} // 運行時 tsc ***.ts --target ES5 -w --experimentalDecorators @useSalutation("Mr. ") class Greeter { constructor(public name: string) { } sayHello() { console.log(`Hello ${this.name}`) }; } const grt = new Greeter('Smith'); grt.sayHello(); => Hello Mr. Smith
(4)函數(shù)裝飾器
(1) target 引用定義函數(shù)的實例類的對象 propertyKey 被裝飾的函數(shù)的名稱 descriptor 被裝飾的函數(shù)的標(biāo)識符,含一個 value 屬性,存儲被裝飾函數(shù)的原始代碼。 修改該屬性,可以修改被裝飾函數(shù)的原始代碼。 function logTrade(target, propertyKey, descriptor) { descriptor.value = function () { console.log(`Invoked ${propertyKey} providing:`, arguments); } } class Trade { @logTrade placeOrder(stockName: string, quantity: number, operation: string, tradedID: number) {} } const trade = new Trade(); trade.placeOrder('IBM', 100, 'Buy', 123); => Invoked placeOrder providing: [Arguments] {'0':'IBM','1':100,'2':'Buy','3': 123}
(5)執(zhí)行順序
屬性 > 方法 > 方法參數(shù) > 類,多個同樣的裝飾器,它會先執(zhí)行后面的裝飾器。// 類裝飾器function anotationClass(id) { console.log('anotationClass evaluated', id); return (target) => console.log('Class executed', id);}// 方法裝飾器 function anotationMethods(id) { console.log('anotationMethods evaluated', id); return (target, property, descriptor) => console.log('Methods executed', id); } @anotationClass(1) @anotationClass(2) class Example { @anotationMethods(1) @anotationMethods(2) method() { } } // Methods evaluated 1 // Methods evaluated 2 // Methods executed 2 // Methods executed 1 // Class evaluated 1 // Class evaluated 2 // Class executed 2 // Class executed 1
映射類型
1.Readonly:只讀映射類型,將先前聲明的類型的所有屬性都調(diào)整為 Readonly。
原理 : type Readonly<T> = { //索引類型查詢,表示屬性名的聯(lián)合 Readonly [P in keyof T]: T[P] //表示將給定類型 T 的所用屬性聯(lián)合給 P,T[p]是查詢類型,表示類型為 T[p]的屬性。 } Eg:interface Person { name: string age: number } type propNames = keyof Person // type propNames = "name"|"age" type propTypes = Person[propNames] // type propTypes = string | number const worker: Person = { name: 'John', age: 22 } function doStuff(person: Readonly<Person>) { person.age = 25 =>無法分配到 "age" ,因為它是只讀屬性。 } keyof 和 T[p] 應(yīng)用 interface Person { name: string; age: number; } const persons: Person[] = [ { name: 'John', age: 32 }, { name: 'Mary', age: 33 }, ]; function filterBy<T, P extends keyof T>( property: P, value: T[P], array: T[]) { return array.filter(item => item[property] === value); } console.log(filterBy('name', 'John', persons)); console.log(filterBy('lastName', 'John', persons)); // error console.log(filterBy('age', 'twenty', persons)); // error
2.Partial:
//所有屬性可選,原理 → type Partial<T> = { [P in keyof T]?: T[P] }
3.Required
//所有屬性都必須,原理 → type Required<T> = { [P in keyof T]-?: T[P] }
4.Pick
//選擇給定類型屬性的子集聲明新類型 type Pick<T, K extends keyof T> ={ [P in K]: T[P] }
5.多個映射類型
Readonly<Partial<Person>>
6.自定義
type Modifiable<T> = { -readonly [P in keyof T]: T[P] } type NewPromise<T> = T extends (...args: infer A) => infer R ? (...args: A) => Promise<R> : T; type Promisify<T> = { [P in keyof T]: NewPromise<T[P]> }
條件類型
1.T extends U ? X : Y
含義:檢查是否 T 可以分配給 U,如果為真,則使用類型 X,否則使用類型 Y。
2.Exclude 類型
原理: type Exclude<T, U> = T extends U ? never : T 含義:若果 T 不能分配給
U,這保留它,否則過濾掉它。 Eg:刪除 Person 類型中的 name 和 age 屬性。
class Person { id: number; name: string; age: number;}type RemoveProps<T, K> = Exclude<keyof T, K>type RemainingProps = RemoveProps<Person, 'name' | 'age'>;<=> 'id' | 'name' | 'age' extends 'name' | 'age' ? never : 'id' | 'name' | 'age' <=> RemainingProps = 'id'type PersonBlindAuditions = Pick<Person, RemainingProps>;<=> 表示 Person 類屬性子集的聯(lián)合被重新聲明新類型<=> 結(jié)果 type PersonBlindAuditions = { id: number}
3.infer 關(guān)鍵字文章來源:http://www.zghlxwxcb.cn/news/detail-651072.html
type ReturnType = T extends (…args: infer A) => infer R ?
含義:該類型是一個函數(shù),參數(shù)為任意數(shù)量的 infer A 類型,返回值為 infer R 類型。 應(yīng)用:將類中的方法轉(zhuǎn)化為異步方法文章來源地址http://www.zghlxwxcb.cn/news/detail-651072.html
interface SyncService { baseUrl: string; getA(): string; } type ReturnPromise<T> = T extends (...args: infer A) => infer R ? (...args: A) => Promise<R> : T; type Promisify<T> = { [P in keyof T]: ReturnPromise<T[P]>; }; class AsyncService implements Promisify<SyncService> { baseUrl: string; getA(): Promise<string> { return Promise.resolve(''); } } let service = new AsyncService(); let result = service.getA(); // hover answer——let result: Promise<string>
到了這里,關(guān)于TypeScript入門指南:特性、安裝配置、類型聲明、編譯選項、面向?qū)ο蟮仍斀獾奈恼戮徒榻B完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!