TypeScript 是一門基於 JavaScript 之上的編程語言,它重點解決了 JavaScript 語言自己類型系統不足的問題。javascript
強類型:具備類型約束 不容許隱式類型轉換 約束後,不符合類型的編譯階段就會報錯,而不是執行階段html
弱類型:不具備類型約束 容許隱式類型轉換java
靜態類型 一個變量聲明時他的類型就是明確的,而且不可修改node
動態類型 運行階段才能夠明確變量類型,並且變量的類型隨時能夠改變git
const obj ={} obj.foo() //只有運行階段才發現錯誤 //若是錯誤放異步中,就會存有隱患 setTimeout(() => { obj.foo() }, 1000000);
//類型不明確致使沒法肯定函數功能 function sum (a,b){ return a+b } console.log(sum(1,2)); console.log(sum("100",100));
相比於弱類型,強類型的優點typescript
2014 facebook
類型註解可控不是都必須加npm
flow安裝編程
npm install flow-bin -D npx flow init //生成.flowconfig
使用flow時關閉vscode的語法校驗,由於添加的類型註解不是標準的js語法數組
文件 -> 首選項 -> 設置 -> javascript validate
添加註釋@flow
,標記進行flow檢查的文件瀏覽器
控制檯使用 yarn flow
會查找node_modules裏的.bin/flow
進行類型檢查
//@flow function sum(n:number,m:number){ return n+m } // console.log(sum("100",100)) //"100"會報錯 console.log(sum(100,200))
yarn flow stop
結束服務
Flow 移除註解
@flow並非js的語法。所以執行 node +文件.js 或瀏覽器中 會在控制檯報錯
編碼事後自動移除掉類型註解
方式1 flow官方移除
yarn add flow-remove-types --dev
yarn flow-remove-types . -d dist
點(改爲src)是全部文件 後面是輸出位置,做用是去除類型註解,在node和瀏覽器中使用方式2 babel插件
安裝:
npm i @babel/core @babel/cli @babel/preset-flow -D
yarn add @babel/core @babel/cli @babel/preset-flow --save
yarn babel src/part2_typescript/ts_typescript_06.js -d dist/js
yarn babel src -d dist
編譯src文件用babelflowFlow vscode插件
Flow 類型推斷
建議仍是添加類型註解
function square(n){ return n * n } // square("100") //n報錯 let num:number = 1 // num = "streing"
Flow類型註解類型
string number boolean null undefined symbol
array object function
const a:string = "1" const b:number = NaN//100, Infinity const c:boolean = true const d:null = null const e:void = undefined const f:symbol = Symbol() const arr:Array<any> = [1,true] const arr1:any[] = [1,true] const fw:[string,number] = ['foow',1] //固定長度類型的數組成爲元組 const obj_:{foo?:string,bar:number} = {foo:"1as",bar:1} //能夠可選 const obj:{[string]:string} = {} //經過key給空對象添加,約定key和value ob.key1 = "value" function fn(callback:(string,number)=>void){ //函數參數指定函數 callback("str",1) } fn(function(str,n){ })
特殊類型
//字面量 const wc:"foo" = "foo" //字面量配合聯合類型 const type:'success' | "warning" | "danger" = "success" const nb: string | number = 1 //類型別名 type StringOrNumber = string | number const sb:StringOrNumber = "stri"
//MayBe類型,在具體類型基礎上擴展了null和undefined兩個值,添加? const gender:?number = null const gender1:number | null | void = undefined //同上 //Mixed Any 任意類型 全部類型的聯合類型 any是弱類型,mixed是強類型 //string | number | boolean function passMix(value:mixed){ // value * value 報錯 // value.split(",") 報錯 if(typeof value === 'string'){ //這個聯合類型須要判斷 value.split(",") } if(typeof value === 'number'){ value * value } } function passAny(value:any){ value * value value.split(",") }
安裝
npm i typscript -D npm i ts-node -D tsc --init
tsc xxx
ts-node xxx
相比較flow 生態健全強大,完善 且漸進式的,什麼不會也徹底看成js用
缺點是多了不少概念,接口泛型枚舉
不一樣文件同名衝突的問題。js不會報錯會覆蓋,可是ts會在顯示階段就提醒你報錯,
所以,經過IIFE
或者 export{}
形式將文件造成私有做用域
//單獨做用域 // (function(){ const hello = (name:string) =>console.log(`Hello,${name}`); hello("TypeScript") //原始類型 //string,number,boolean均可以設置成null or undefined const a:string = "aa" const b:number=1//NaN Infinity const c:boolean= false const d:string = null const e:void = undefined //null const f:null = null const g:undefined = undefined const h:symbol = Symbol() //})() //改爲模塊,全部成員都是局部成員,不是導出了個對象 export {}
首選項 typescript local -> zh-CN
修改爲中文錯誤提示
object類型
//Object類型不單指對象,而是原始類型之外的其餘類型, //`number,string,boolean,symbol,null或undefined`以外的類型 const foo:object = function (){}//{},[] const obj:{foo:number,bar:string} = {foo:123,bar:"as"}//這種形式能夠用interface搞定
declare function create(o: object | null): void; create({ prop: 0 }); // OK create(null); // OK create(42); // Error create("string"); // Error create(false); // Error create(undefined); // Error
array類型
const arr:Array<number> = [1,2,3] const arr2:number[] = [1,2,3] function sum(...args:number[]){ return args.reduce((executor,current)=>{ return executor+current }) } console.log(sum(1,2,3))
元組
//明確元素數量和元素類型的數組 const tuple:[number,string] = [1,"1"] tuple[0] const [age,name] = tuple
枚舉
const status = { Before:0, Doing:1, After:2 } //默認從0開始累加,枚舉會影響咱們編譯後的結果(看下編譯的js文件), enum Status{ Before, Doing, After // After = "aff" //字符串枚舉,不常見 } // const enum Status{ //加const爲常量枚舉 // Before, // Doing, // After // } const s = { current:Status.Doing } console.log(s); //有const 不能經過索引訪問枚舉名 console.log(Status[0])
函數類型
//函數類型 function sth(a:number,b?:number,c:number=10):string { return "" } function sth1(a:number,...args:number[]):string { return "" } const sth2:(a:number,b:number)=>string = function (a:number,b:number):string { return "" }
任意類型
//any不會作類型檢查,語法上不會報錯 function sth3(s:any){ }
隱式類型推斷
//(建議添加明確類型) let num = 18 // num = "" //類型錯誤 let fx //any類型
類型斷言
//並非類型轉換,代碼編譯事後不存在了就 const nums = 1; const mn = nums as number const mn2 = <number>nums //jsx 不支持
接口 interface
約定一個對象有哪些成員,這些成員類型是什麼
接口就是用來約束對象的結構,一個對象實現一個接口他就必須擁有接口所約束的成員
接口只是類型約束,運行階段就沒了
interface Person{ age:number //逗號,分號,不加 name:string sex?:string readonly height:number [key:string]:any } function student(s:Person) { console.log(s.age); console.log(s.name); } const stud:Person = { age:1, name:"as", height:199 } // stud.height = 180 stud.va = "asd" stud.as = 112
函數類型接口
interface SearchFunc { (source: string, subString: string): boolean; }
let mySearch = <SearchFunc>function(source: string, subString: string) { let result = source.search(subString); return result > -1; }
類類型接口
interface ClockInterface { currentTime: Date; setTime(d: Date); } class Clock implements ClockInterface { currentTime: Date; setTime(d: Date) { this.currentTime = d; } constructor(h: number, m: number) { } }
類靜態部分與實例部分的區別
當你操做類和接口的時候,你要知道類是具備兩個類型的:靜態部分的類型和實例的類型。 你會注意到,當你用構造器簽名去定義一個接口並試圖定義一個類去實現這個接口時會獲得一個錯誤:
interface ClockConstructor { new (hour: number, minute: number); } class Clock implements ClockConstructor { currentTime: Date; constructor(h: number, m: number) { } }
這裏由於當一個類實現了一個接口時,只對其實例部分進行類型檢查。 constructor存在於類的靜態部分,因此不在檢查的範圍內
所以,咱們應該直接操做類的靜態部分。 看下面的例子,咱們定義了兩個接口, ClockConstructor
爲構造函數所用和ClockInterface
爲實例方法所用。 爲了方便咱們定義一個構造函數 createClock
,它用傳入的類型建立實例。
interface ClockConstructor { new (hour: number, minute: number): ClockInterface; } interface ClockInterface { tick(); } function createClock(ctor: ClockConstructor, hour: number, minute: number): ClockInterface { return new ctor(hour, minute); } class DigitalClock implements ClockInterface { constructor(h: number, m: number) { } tick() { console.log("beep beep"); } } let digital = createClock(DigitalClock, 12, 17);
接口繼承
interface Shape { color: string; } interface PenStroke { penWidth: number; } interface Square extends Shape, PenStroke { sideLength: number; } let square = <Square>{}; square.color = "blue"; square.sideLength = 10; square.penWidth = 5.0;
描述一類具體事務的抽象特徵 (手機)
聲明,修飾符,構造函數,靜態方法
class Person{ name:string //要聲明相比js(es7) private age:number //默認public protected gender:boolean readonly sex:string = "as" //只讀 constructor(name:string,age:number){ this.name = name this.age = age } say(msg:string):void{ console.log(`hi ${this.name},${msg}`); } } const mc = new Person("mcgee",18) mc.name // mc.age // mc.gender
class Student extends Person{ constructor(name:string,age:number){ super(name,age) console.log(this.gender); //可訪問 } }
class Student2 extends Person{ private constructor(name:string,age:number){ //構造函數添加private 則沒法實例化,沒法被繼承 super(name,age) console.log(this.gender); } static create(name:string,age:number){ return new Student2(name,age) } } // new Student2("MC",16) //錯 Student2.create("MC",16) //能夠 //給構造函數添加protected 沒法被實例化,可是能夠被繼承
類與接口
類與類之間有公共特徵,經過接口抽象 (手機和座機都能打電話)
interface Eat{ eat (food:string):void } interface Run{ run (distance:number):void } class Person implements Eat,Run{ //類實現了接口必須有接口的成員 eat(food:string){ } run(distance:number){ } } // class Animal implements EatAndRun{ // eat(food:string){ // } // run(distance:number){ // } // }
抽象類
相似於接口,約束子類中必須有某個成員,區別是抽象類能夠包含一些具體的實現,接口只能是成員的抽象不包含具體實現
抽象類只能被繼承,不能new
abstract class Animal{ eat(food:string):void{ console.log(food); } abstract run(distance:number):void //抽象方法不須要方法體 } class Dog extends Animal{ run(distance:number):void{ } } const d = new Dog() d.eat("sss") d.run(100)
泛型
定義函數,接口或類的時候沒有指定具體類型,等到咱們使用的時候再去指定具體類型
目的是極大程度的複用代碼
function arraynumber(length:number,value:number) :number[]{ return Array<number>(length).fill(value) } const res = arraynumber(3,100) //[100,100,100] //若是再定一個arraystring function arraystring(length:number,value:string) :string[]{ return Array<string>(length).fill(value) } //把定義時不能明確的類型變成參數,使用時傳遞 function createArray<T>(length:number,value:T):T[]{ return Array<T>(length).fill(value) } createArray<string>(4,"mcgee")
泛型類型
function identity<T>(arg: T): T { return arg; } let myIdentity: <U>(arg: U) => U = identity;
//泛型類型接口 interface GenericIdentityFn { <T>(arg: T): T; } function identity<T>(arg: T): T { return arg; } let myIdentity: GenericIdentityFn = identity;
//綁定了接口泛型類型 interface GenericIdentityFn<T> { (arg: T): T; } function identity<T>(arg: T): T { return arg; } let myIdentity: GenericIdentityFn<number> = identity;
泛型類
class GenericNumber<T> { zeroValue: T; add: (x: T, y: T) => T; } let myGenericNumber = new GenericNumber<number>(); myGenericNumber.zeroValue = 0; myGenericNumber.add = function(x, y) { return x + y; };
泛型約束
//泛型T知足接口length屬性 interface Lengthwise { length: number; } function loggingIdentity<T extends Lengthwise>(arg: T): T { console.log(arg.length); // Now we know it has a .length property, so no more error return arg; }
類型聲明
引入第三方模塊時候,若是第三方模塊不包含類型聲明,能夠自聲明
引入 query-string
import {camelCase} from 'lodash' //@types/lodash import qs from 'query-string' declare function camelCase (input:string):string //添加後res:string const res = camelCase('hello camelCase') //res:any qs.parse("?key=asdasdq122") //自帶類型約束