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") //自带类型约束