TypeScript快速入门 TypeScript 是一种由微软开发的自由和开源的编程语言。
它是 JavaScript 的一个超集,本质是向这个语言添加可选的静态类型和基于类的面向对象编程。
使用TypeScript 编译器 安装TypeScript 1 npm install -g typescript
编译 TypeScript 文件 1 2 3 4 tsc hello.ts node hello.js
对于刚入门 TypeScript 的小伙伴,也可以不用安装 typescript
直接使用线上的 TypeScript Playground 来学习新的语法或新特性。
编译完成后,目录中会出现hello.js
,其中内容与ts
中的一模一样,然后node hello.js
就会进行输出。
细心的同学,可能会发现。当函数名或者是变量名相同的时候,会提示重复定义的问题,此时就应该优化编译方法
优化编译
解决TS和JS变量冲突问题,会生成tsconfig.json
配置文件
自动编译,生成dist文件夹,里面存放着编译好的js文件
发出错误
1 tsc --noEmitOnError hello.ts
nodejs环境执行ts
1 2 npm i @types/node --save-dev // node环境支持的依赖必装 npm i ts-node --g
降级编译 降级ES6语法,适配浏览器。
1 2 tsconfig.json : "target" :"es5" ,
严格模式 1 2 3 4 tsconfig.json : "strict" :true , "noImplicitAny" :true , "strictNullChecks" :true ,
基元类型 基础类型 :Boolean、Number、String、null、undefined 以及 ES6 的 Symbol 和 ES10 的 BigInt。
字符串类型(string) 字符串是使用string 定义的
1 2 3 4 let a : string = '123' let str : string = `dddd${a} `
数字类型(number) 支持十六进制、十进制、八进制和二进制
1 2 3 4 5 6 7 let notANumber : number = NaN ;let num : number = 123 ;let infinityNumber : number = Infinity ;let decimal : number = 6 ;let hex : number = 0xf00d ;let binary : number = 0b1010 ;let octal : number = 0o744 ;
布尔类型(boolean)
注意,使用构造函数 Boolean 创造的对象不是布尔值
1 2 let createdBoolean : boolean = new Boolean (1 )
事实上 new Boolean()
返回的是一个 Boolean 对象
(valueOf可以读值)需要改成
1 2 let booleand : boolean = true let booleand2 : boolean = Boolean (1 )
空值类型(void) JavaScript 没有空值(Void)的概念,在 TypeScript 中,可以用 void 表示没有任何返回值的函数
1 2 3 function voidFn ( ): void { console .log ('test void' ) }
void 类型的用法,主要是用在我们不希望 调用者关心函数返回值的情况下,比如通常的异步回调函数
void也可以定义undefined 和 null类型
1 2 let u : void = undefined let n : void = null ;
Null和undefined类型 1 2 let u : undefined = undefined ;let n : null = null ;
void
和 undefined
和 null
最大的区别
与 void 的区别是,undefined 和 null 是所有类型的子类型 。
也就是说 undefined 类型的变量,可以赋值给 string 类型的变量:
1 2 3 4 5 let test : void = undefined let num2 : string = "1" num2 = test
1 2 3 4 5 6 7 8 9 10 11 let test : null = null let num2 : string = "1" num2 = test let test : undefined = undefined let num2 : string = "1" num2 = test
注意,如果你配置了tsconfig.json
开启了严格模式
那么要注意null不能赋予void类型
任意类型 Any 类型 和 unknown 顶级类型
没有强制限定哪种类型,随时切换类型都可以 我们可以对 any 进行任何操作,不需要检查类型
1 2 3 let anys :any = 123 anys = '123' anys = true
声明变量的时候没有指定任意类型默认为any
1 2 3 let anys;anys = '123' anys = true
缺点 :
如果使用any 就失去了TS类型检测的作用
TypeScript 3.0中引入的 unknown 类型
也被认为是 top type ,但它更安全。
与 any 类型一样,所有类型都可以分配给unknown
unknow类型比any类型更加严格 ,当你要使用any 的时候可以尝试使用unknow
区别 :
注意:
unknow类型不能作为子类型只能作为父类型,any可以作为父类型和子类型
unknown类型不能赋值给其他类型,any类型可以
unknown可赋值对象只有unknown 和 any
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 let value : unknown; value = true ; value = 42 ; value = "Hello World" ; value = []; value = {}; value = null ; value = undefined ; value = Symbol ("type" ); let names :unknown = '123' let names2 :string = names let names :any = '123' let names2 :string = names let bbb :unknown = '123' let aaa :any= '456' aaa = bbb
1 2 3 4 5 6 7 8 let obj :any = {b :1 }obj.a let obj :unknown = {b :1 ,ccc :():number =>213 }obj.b obj.ccc ()
接口和对象类型 对象类型 在typescript中,我们定义对象的方式要用关键字interface (接口),定义方式如下:
大佬的理解是使用interface 来定义一种约束,让数据结构满足约束的格式
1 2 3 4 5 6 7 8 9 10 11 interface Person { b :string, a :string } const person :Person = { a :"213" }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 interface A{name :string} interface A{age :number} var x :A={name :'xx' ,age :20 }interface A{ name :string } interface B extends A{ age :number } let obj :B = { age :18 , name :"string" }
可选属性 使用 ? 操作符 1 2 3 4 5 6 7 8 9 10 interface Person { b?:string, a :string } const person :Person = { a :"213" }
任意属性 [propName: string]
需要注意的是,一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集 :
1 2 3 4 5 6 7 8 9 10 11 12 13 interface Person { b?:string, a :string, [propName : string]: any; } const person :Person = { a :"213" , c :"123" }
只读属性 readonly readonly 只读属性
是不允许被赋值,只能读取
1 2 3 4 5 6 7 8 9 10 11 12 13 14 interface Person { b?: string, readonly a : string, [propName : string]: any; } const person : Person = { a : "213" , c : "123" } person.a = 123
添加函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 interface Person { b?: string, readonly a : string, [propName : string]: any; cb ():void } const person : Person = { a : "213" , c : "123" , cb :()=> { console .log (123 ) } }
数组类型 类型[ ]
注意不能使用数组的操作方法进行添加 ,例如unshift()
1 2 3 4 5 6 7 8 9 10 11 12 13 let arr :number[] = [123 ]let arr :number[] = [1 ,2 ,3 ,'1' ]let arr :number[] = [1 ,2 ,3 ,]arr.unshift ('1' ) var arr : number[] = [1 , 2 , 3 ]; var arr2 : string[] = ["1" , "2" ]; var arr3 : any[] = [1 , "2" , true ]; let arr :number[][][] = [[[]],[[]],[[]]]
数组泛型(Array<类型>
) 1 2 3 let arr :Array <number> = [1 ,2 ,3 ,4 ,5 ]let arr :Array <Array <number | string>> = [[1 ,2 ,3 ,'123' ],[4 ,5 ,6 ]]
用接口表示数组 一般用来描述类数组
1 2 3 4 5 interface NumberArray { [index : number]: number; } let fibonacci : NumberArray = [1 , 1 , 2 , 3 , 5 ];
arguments类
数组1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function Arr (...args:any ): void { console .log (arguments ) let arr :number[] = arguments } Arr (111 , 222 , 333 )interface IArguments { [index : number]: any; length : number;callee : Function ;} function Arr (...args:any ): void { console .log (arguments ) let arr :IArguments = arguments } Arr (111 , 222 , 333 )
any 在数组中的应用 一个常见的例子数组中可以存在任意类型
1 let list : any[] = ['test' , 1 , [],{a :1 }]
函数扩展 函数类型 1 2 3 4 5 const fn = (name : string, age :number): string => { return name + age } fn ('张三' ,18 )
函数的可选参数? 1 2 3 4 5 const fn = (name : string, age?:number): string => { return name + age } fn ('张三' )
函数参数的默认值 1 2 3 4 const fn = (name : string = "我是默认值" ): string => { return name } fn ()
接口定义函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 interface Add { (num : number, num2 : number): number } const fn : Add = (num : number, num2 : number): number => { return num + num2 } fn (5 , 5 )interface User { name : string; age : number; } function getUserInfo (user: User ): User { return user }
定义剩余参数 1 2 3 4 5 6 7 8 const fn = (array :number[],...items :any[]):any[] => { console .log (array,items) return items } let a :number[] = [1 ,2 ,3 ]fn (a,'4' ,'5' ,'6' )
函数重载 重载:方法名字相同,而参数不同,返回类型可以相同也可以不同。
如果参数类型不同,则参数类型应设置为 any。
参数数量不同你可以将不同的参数设置为可选。
1 2 3 4 5 6 7 8 9 function fn (params: number ): void function fn (params: string, params2: number ): void function fn (params: any, params2?: any ): void console .log (params) console .log (params2) } fn (123 fn ('123' ,456 )
类型断言 | 联合类型 | 交叉类型 联合类型 1 2 3 4 5 6 let myPhone : number | string = '010-820' let myPhone : number | string = true
函数使用联合类型
1 2 3 const fn = (something :number | boolean):boolean => { return !!something }
交叉类型 多种类型的集合,联合对象将具有所联合类型的所有成员
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 interface People { age : number, height: number } interface Man { sex : string } const xiaoman = (man: People & Man ) => { console .log (man.age ) console .log (man.height ) console .log (man.sex ) } xiaoman ({age : 18 ,height :180 ,sex :'male' });
类型断言(疑惑点) 语法:值 as 类型 或者 <类型> 值
用途 :
(1)将一个联合类型推断为其中一个类型
(2)将一个父类断言为更加具体的子类
(3)将任何一个类型断言为any
(4)将any断言为一个具体的类型
1 2 3 4 5 6 7 8 9 10 11 12 interface A { run : string } interface B { build : string } const fn = (type : A | B): string => { return type.run }
1 2 3 4 5 6 7 8 9 10 11 12 interface A { run : string } interface B { build : string } const fn = (type : A | B): string => { return (type as A).run }
需要注意的是,类型断言只能够「欺骗」TypeScript 编译器,无法避免运行时的错误,反而滥用类型断言可能会导致运行时错误
使用any临时断言
1 2 (window as any).abc = 123
as const 是对字面值的断言 ,与const直接定义常量是有区别的
如果是普通类型跟直接const 声明是一样的
1 2 3 4 5 const names = '小满' names = 'aa' let names2 = '小满' as const names2 = 'aa'
1 2 3 4 5 6 let a1 = [10 , 20 ] as const ;const a2 = [10 , 20 ];a1.unshift (30 ); a2.unshift (30 );
类型断言是不具影响力的 在下面的例子中,将 something 断言为 boolean 。
虽然可以通过编译,但是并没有什么用 ,并不会影响结果,因为编译过程中会删除类型断言
1 2 3 4 5 6 function toBoolean (something: any ): boolean { return something as boolean; } toBoolean (1 );
内置对象 JavaScript 中有很多内置对象 ,它们可以直接在 TypeScript 中当做定义好了的类型。
ECMAScript 的内置对象 Boolean、Number、string、RegExp、Date、Error
1 2 3 4 5 6 7 8 9 10 11 12 let b : Boolean = new Boolean (1 )console .log (b)let n : Number = new Number (true )console .log (n)let s : String = new String ('哔哩哔哩关注小满zs' )console .log (s)let d : Date = new Date ()console .log (d)let r : RegExp = /^1/ console .log (r)let e : Error = new Error ("error!" )console .log (e)
DOM 和 BOM 的内置对象 Document、HTMLElement、Event、NodeList 等
1 2 3 4 5 6 7 let body : HTMLElement = document .body ;let allDiv : NodeList = document .querySelectorAll ('div' );let div :HTMLElement = document .querySelector ('div' ) as HTMLDivElement document .addEventListener ('click' , function (e: MouseEvent ) { });
DOM元素的映射表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 interface HTMLElementTagNameMap { "a" : HTMLAnchorElement ; "abbr" : HTMLElement ; "address" : HTMLElement ; "applet" : HTMLAppletElement ; "area" : HTMLAreaElement ; "article" : HTMLElement ; "aside" : HTMLElement ; "audio" : HTMLAudioElement ; "b" : HTMLElement ; "base" : HTMLBaseElement ; "bdi" : HTMLElement ; "bdo" : HTMLElement ; "blockquote" : HTMLQuoteElement ; "body" : HTMLBodyElement ; "br" : HTMLBRElement ; "button" : HTMLButtonElement ; "canvas" : HTMLCanvasElement ; "caption" : HTMLTableCaptionElement ; "cite" : HTMLElement ; "code" : HTMLElement ; "col" : HTMLTableColElement ; "colgroup" : HTMLTableColElement ; "data" : HTMLDataElement ; "datalist" : HTMLDataListElement ; "dd" : HTMLElement ; "del" : HTMLModElement ; "details" : HTMLDetailsElement ; "dfn" : HTMLElement ; "dialog" : HTMLDialogElement ; "dir" : HTMLDirectoryElement ; "div" : HTMLDivElement ; "dl" : HTMLDListElement ; "dt" : HTMLElement ; "em" : HTMLElement ; "embed" : HTMLEmbedElement ; "fieldset" : HTMLFieldSetElement ; "figcaption" : HTMLElement ; "figure" : HTMLElement ; "font" : HTMLFontElement ; "footer" : HTMLElement ; "form" : HTMLFormElement ; "frame" : HTMLFrameElement ; "frameset" : HTMLFrameSetElement ; "h1" : HTMLHeadingElement ; "h2" : HTMLHeadingElement ; "h3" : HTMLHeadingElement ; "h4" : HTMLHeadingElement ; "h5" : HTMLHeadingElement ; "h6" : HTMLHeadingElement ; "head" : HTMLHeadElement ; "header" : HTMLElement ; "hgroup" : HTMLElement ; "hr" : HTMLHRElement ; "html" : HTMLHtmlElement ; "i" : HTMLElement ; "iframe" : HTMLIFrameElement ; "img" : HTMLImageElement ; "input" : HTMLInputElement ; "ins" : HTMLModElement ; "kbd" : HTMLElement ; "label" : HTMLLabelElement ; "legend" : HTMLLegendElement ; "li" : HTMLLIElement ; "link" : HTMLLinkElement ; "main" : HTMLElement ; "map" : HTMLMapElement ; "mark" : HTMLElement ; "marquee" : HTMLMarqueeElement ; "menu" : HTMLMenuElement ; "meta" : HTMLMetaElement ; "meter" : HTMLMeterElement ; "nav" : HTMLElement ; "noscript" : HTMLElement ; "object" : HTMLObjectElement ; "ol" : HTMLOListElement ; "optgroup" : HTMLOptGroupElement ; "option" : HTMLOptionElement ; "output" : HTMLOutputElement ; "p" : HTMLParagraphElement ; "param" : HTMLParamElement ; "picture" : HTMLPictureElement ; "pre" : HTMLPreElement ; "progress" : HTMLProgressElement ; "q" : HTMLQuoteElement ; "rp" : HTMLElement ; "rt" : HTMLElement ; "ruby" : HTMLElement ; "s" : HTMLElement ; "samp" : HTMLElement ; "script" : HTMLScriptElement ; "section" : HTMLElement ; "select" : HTMLSelectElement ; "slot" : HTMLSlotElement ; "small" : HTMLElement ; "source" : HTMLSourceElement ; "span" : HTMLSpanElement ; "strong" : HTMLElement ; "style" : HTMLStyleElement ; "sub" : HTMLElement ; "summary" : HTMLElement ; "sup" : HTMLElement ; "table" : HTMLTableElement ; "tbody" : HTMLTableSectionElement ; "td" : HTMLTableDataCellElement ; "template" : HTMLTemplateElement ; "textarea" : HTMLTextAreaElement ; "tfoot" : HTMLTableSectionElement ; "th" : HTMLTableHeaderCellElement ; "thead" : HTMLTableSectionElement ; "time" : HTMLTimeElement ; "title" : HTMLTitleElement ; "tr" : HTMLTableRowElement ; "track" : HTMLTrackElement ; "u" : HTMLElement ; "ul" : HTMLUListElement ; "var" : HTMLElement ; "video" : HTMLVideoElement ; "wbr" : HTMLElement ; }
定义Promise 如果我们不指定返回的类型TS是推断不出来返回的是什么类型
指定返回的类型
函数定义返回promise 语法规则:Promise<T>
类型
当你在使用一些常用的方法的时候,TypeScript 实际上已经帮你做了很多类型判断的工作了
而他们的定义文件,则在 TypeScript 核心库的定义文件 中
Class类 定义类 1 2 3 4 5 6 7 8 9 class Person { constructor () { } run () { } }
在TypeScript是不允许直接在constructor 定义变量的 需要在constructor上面先声明
如果了定义了变量不用 也会报错 通常是给个默认值 或者 进行赋值
类的修饰符 类的修饰符共有3个:public、private、protected
使用public 修饰符
可以让你定义的变量 内部访问 也可以外部访问 如果不写默认就是public
使用 private 修饰符
代表定义的变量私有的只能在内部访问 不能在外部访问
使用 protected 修饰符
代表定义的变量私有的只能在内部和继承的子类中访问 不能在外部访问
Static 静态属性 和 静态方法 我们用static 定义的属性 不可以通过this 去访问 只能通过类名去调用
static 静态函数 同样也是不能通过this 去调用 也是通过类名去调用
注意:如果两个函数都是static 静态的是可以通过this互相调用
interface 定义 类 ts interface 定义类 使用关键字 implements
后面跟interface的名字多个用逗号隔开 继承还是用extends
抽象类 应用场景 :如果你写的类实例化之后毫无用处,此时可以把他定义为抽象类
或者你也可以把他作为一个基类-> 通过继承一个派生类去实现基类的一些方法
例子1 :下面这段代码会报错抽象类无法被实例化
1 2 3 4 5 6 abstract class A { public name :string } new A ()
例子2 :我们在A类定义了 getName 抽象方法但没有实现
我们B类实现了A定义的抽象方法,如不实现就不报错,我们定义的抽象方法必须在派生类实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 abstract class A { name : string constructor (name: string ) { this .name = name; } print (): string { return this .name } abstract getName (): string } class B extends A { constructor ( ) { super ('小满' ) } getName (): string { return this .name } } let b = new B (); console .log (b.getName ());
元组类型 如果需要一个固定大小的不同类型值的集合,我们需要使用元组 。
元组其实就是数组的变种,元组(Tuple)是固定数量的不同类型的元素的组合 。
元组与集合的不同之处 在于,元组中的元素类型可以是不同的,而且数量固定。
元组的好处 在于可以把多个元素作为一个单元传递。如果一个方法需要返回多个值,可以把这多个值作为元组返回,而不需要创建额外的类来表示。
1 2 3 let arr :[number,string] = [1 ,'string' ]let arr2 : readonly [number,boolean,string,undefined ] = [1 ,true ,'sring' ,undefined ]
当赋值或访问一个已知索引的元素时,会得到正确的类型:
1 2 3 4 5 let arr :[number,string] = [1 ,'string' ]arr[0 ].length arr[1 ].length
越界元素 1 2 3 let arr :[number,string] = [1 ,'string' ]arr.push (true )
对于越界的元素他的类型被限制为 联合类型 (就是你在元组中定义的类型)如下图
应用场景 例如定义execl返回的数据
1 2 3 4 5 6 7 let excel : [string, string, number, string][] = [ ['title' , 'name' , 1 , '123' ], ['title' , 'name' , 1 , '123' ], ['title' , 'name' , 1 , '123' ], ['title' , 'name' , 1 , '123' ], ['title' , 'name' , 1 , '123' ], ]
枚举类型 在javaScript中是没有枚举 的概念的TS帮我们定义了枚举这个类型
使用枚举 通过enum关键字 定义我们的枚举
数字枚举 例如:红绿蓝 Red = 0 Green = 1 Blue= 2 分别代表红色0 绿色为1 蓝色为2
1 2 3 4 5 enum Types { Red , Green , BLue }
这样写就可以实现应为ts定义的枚举中的每一个组员默认都是从0开始的所以也就是
1 2 3 4 5 6 enum Types { Red = 0 , Green = 1 , BLue = 2 }
增长枚举 1 2 3 4 5 enum Types { Red = 1 , Green , BLue }
如上,我们定义了一个数字枚举, Red使用初始化为 1。 其余的成员会从 1开始自动增长。 换句话说, Type.Red的值为 1, Green为 2, Blue为 3。
字符串枚举 在一个字符串枚举里,每个成员都必须用字符串字面量,或对另外一个字符串枚举成员进行初始化。
1 2 3 4 5 enum Types { Red = 'red' , Green = 'green' , BLue = 'blue' }
由于字符串枚举没有自增长的行为,字符串枚举可以很好的序列化。 换句话说,如果你正在调试并且必须要读一个数字枚举的运行时的值,这个值通常是很难读的 - 它并不能表达有用的信息,字符串枚举允许你提供一个运行时有意义的并且可读的值,独立于枚举成员的名字。
异构枚举 枚举可以混合字符串和数字成员
1 2 3 4 enum Types { No = "No" , Yes = 1 , }
接口枚举 定义一个枚举Types 定义一个接口A ,他有一个属性red ,值为Types.yyds
声明对象的时候要遵循这个规则
1 2 3 4 5 6 7 8 9 10 11 enum Types { yyds, dddd } interface A { red :Types .yyds } let obj :A = { red :Types .yyds }
const枚举 let 和 var 都是不允许的声明,只能使用const
大多数情况下,枚举是十分有效的方案。
然而在某些情况下需求很严格。
为了避免在额外生成的代码上的开销和额外的非直接的对枚举成员的访问,我们可以使用 const枚举。
常量枚举通过在枚举上使用 const修饰符来定义
const 声明的枚举会被编译成常量
普通声明的枚举编译完后是个对象
1 2 3 4 const enum Types { No = "No" , Yes = 1 , }
Const 声明编译之后
普通声明编译之后
反向映射 它包含了正向映射( name -> value)和反向映射( value -> name)
要注意的是 不会为字符串枚举成员生成反向映射。
1 2 3 4 5 6 7 enum Enum { fall } let a = Enum .fall ;console .log (a); let nameOfA = Enum [a]; console .log (nameOfA);
类型推论|类型别名 类型推断 我声明了一个变量但是没有定义类型
TypeScript会在没有明确的指定类型的时候推测出一个类型,这就是类型推论
不能够在赋值给别的类型
如果你声明变量没有定义类型也没有赋值这时候TS会推断成any类型可以进行任何操作\
类型别名 type 关键字(可以给一个类型定义一个名字)多用于复合类型
定义类型别名
1 2 3 type str = string let s :str = "我是小满" console .log (s);
定义函数别名
1 2 3 type str = () => string let s : str = () => "我是小满" console .log (s);
定义联合类型别名
1 2 3 4 type str = string | number let s : str = 123 let s2 : str = '123' console .log (s,s2);
定义值的别名
1 2 3 type value = boolean | 0 | '213' let s :value = true
symbol类型 symbol
类型的值是通过Symbol
构造函数创建的。
可以传递参数做为唯一标识,只支持 string 和 number类型的参数
1 2 let sym1 = Symbol ();let sym2 = Symbol ("key" );
Symbol的值是唯一的 1 2 3 const s1 = Symbol ()const s2 = Symbol ()
用作对象属性的键 1 2 3 4 5 let sym = Symbol ();let obj = { [sym]: "value" }; console .log (obj[sym]);
使用symbol定义的属性,是不能通过如下方式遍历拿到的 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 const symbol1 = Symbol ('666' )const symbol2 = Symbol ('777' )const obj1= { [symbol1]: '小满' , [symbol2]: '二蛋' , age : 19 , sex : '女' } for (const key in obj1) { console .log (key) } Object .keys (obj1)console .log (Object .keys (obj1))console .log (Object .getOwnPropertyNames (obj1))console .log (JSON .stringify (obj1))
如何拿到
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Object .getOwnPropertySymbols (obj1)console .log (Object .getOwnPropertySymbols (obj1))Reflect .ownKeys (obj1)console .log (Reflect .ownKeys (obj1))var arr = [1 ,2 ,3 ,4 ];let iterator = arr[Symbol .iterator ]();console .log (iterator.next ()); console .log (iterator.next ()); console .log (iterator.next ()); console .log (iterator.next ()); console .log (iterator.next ());
测试用例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 interface Item { age : number , name : string } const array : Array <Item > = [{ age : 123 , name : "1" }, { age : 123 , name : "2" }, { age : 123 , name : "3" }]type mapTypes = string | number const map :Map <mapTypes,mapTypes> = new Map ()map.set ('1' ,'王爷' ) map.set ('2' ,'陆北' ) const obj = { aaa :123 , bbb :456 } let set :Set <number > = new Set ([1 ,2 ,3 ,4 ,5 ,6 ])const gen = (erg :any ): void => { let it : Iterator <any > = erg[Symbol .iterator ]() let next :any = { done : false } while (!next.done ) { next = it.next () if (!next.done ) { console .log (next.value ) } } } gen (array)
以下为这些symbols 的列表:
Symbol.hasInstance 方法,会被instanceof运算符调用。构造器对象用来识别一个对象是否是其实例。
Symbol.isConcatSpreadable 布尔值,表示当在一个对象上调用Array.prototype.concat时,这个对象的数组元素是否可展开。
Symbol.iterator 方法,被for-of语句调用。返回对象的默认迭代器。
Symbol.match 方法,被String.prototype.match调用。正则表达式用来匹配字符串。
Symbol.replace 方法,被String.prototype.replace调用。正则表达式用来替换字符串中匹配的子串。
Symbol.search 方法,被String.prototype.search调用。正则表达式返回被匹配部分在字符串中的索引。
Symbol.species 函数值,为一个构造函数。用来创建派生对象。
Symbol.split 方法,被String.prototype.split调用。正则表达式来用分割字符串。
Symbol.toPrimitive 方法,被ToPrimitive抽象操作调用。把对象转换为相应的原始值。
Symbol.toStringTag 方法,被内置方法Object.prototype.toString调用。返回创建对象时默认的字符串描述。
Symbol.unscopables 对象,它自己拥有的属性会被with作用域排除在外。
泛型 函数泛型 下面两个函数一个是数字类型的函数,另一个是字符串类型的函数,其实就是类型不同,实现的功能是一样的,这时候我们就可以使用泛型来优化
1 2 3 4 5 6 7 8 9 10 11 function num (a :number ,b :number ) : Array <number > { return [a ,b]; } num (1 ,2 )function str (a :string ,b :string ) : Array <string > { return [a ,b]; } str ('独孤' ,'求败' )
泛型优化 语法 为函数名字后面跟一个<参数名> 参数名可以随便写
例如我这儿写了T,当我们使用这个函数的时候把参数的类型传进去就可以了 (也就是动态类型)
1 2 3 4 5 6 function Add <T>(a : T, b : T): Array <T> { return [a,b] } Add <number >(1 ,2 )Add <string >('1' ,'2' )
我们也可以使用不同的泛型参数名,只要在数量上和使用方式上能对应上就可以。
1 2 3 4 5 6 function Sub <T,U>(a :T,b :U):Array <T|U> { const params :Array <T|U> = [a,b] return params } Sub <Boolean ,number >(false ,1 )
定义泛型接口 声明接口的时候 在名字后面加一个<参数>
使用的时候传递类型
1 2 3 4 5 6 7 8 9 10 11 interface MyInter <T> { (arg : T): T } function fn<T>(arg : T): T { return arg } let result : MyInter <number > = fnresult (123 )
对象字面量泛型
1 2 3 4 5 6 7 let foo : { <T>(arg : T): T }foo = function <T>(arg :T):T { return arg } foo (123 )
泛型约束 我们期望在一个泛型的变量上面,获取其length参数,但是,有的数据类型是没有length属性的
1 2 3 function getLegnth<T>(arg :T) { return arg.length }
这时候我们就可以使用泛型约束
于是,我们就得对使用的泛型进行约束,我们约束其为具有length属性的类型,这里我们会用到interface,代码如下
1 2 3 4 5 6 7 8 9 interface Len { length :number } function getLegnth<T extends Len >(arg :T) { return arg.length } getLegnth<string >('123' )
使用keyof 约束对象 其中使用了TS泛型和泛型约束。
首先定义了T类型并使用extends关键字继承object类型的子类型,然后使用keyof操作符获取T类型的所有键,它的返回类型是联合类型,最后利用extends关键字约束 K类型必须为keyof T联合类型的子类型
1 2 3 4 5 6 7 8 9 function prop<T, K extends keyof T>(obj : T, key : K) { return obj[key] } let o = { a : 1 , b : 2 , c : 3 }prop (o, 'a' ) prop (o, 'd' )
泛型类 声明方法跟函数类似名称后面定义<类型>
使用的时候确定类型new Sub<number>()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Sub <T>{ attr : T[] = []; add (a :T):T[] { return [a] } } let s = new Sub <number >()s.attr = [1 ,2 ,3 ] s.add (123 ) let str = new Sub <string >()str.attr = ['1' ,'2' ,'3' ] str.add ('123' )
namespace命名空间 在工作中无法避免全局变量 造成的污染,TypeScript提供了namespace 避免这个问题出现
内部模块,主要用于组织代码,避免命名冲突。
命名空间内的类默认私有
通过 export
暴露
通过 namespace
关键字定义
TypeScript与ECMAScript 2015一样,任何包含顶级import
或者export
的文件都被当成一个模块。相反地,如果一个文件不带有顶级的import
或者export
声明,那么它的内容被视为全局可见的(因此对模块也是可见的)
命名空间中通过export将想要暴露的部分导出
如果不用export 导出是无法读取其值的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 namespace a { export const Time : number = 1000 export const fn = <T>(arg : T): T => { return arg } fn (Time ) } namespace b { export const Time : number = 1000 export const fn = <T>(arg : T): T => { return arg } fn (Time ) } a.Time b.Time
嵌套命名空间 1 2 3 4 5 6 7 8 9 10 11 12 13 14 namespace a { export namespace b { export class Vue { parameters : string constructor (parameters: string ) { this .parameters = parameters } } } } let v = a.b .Vue new v ('1' )
抽离命名空间 a.ts
1 2 3 export namespace V { export const a = 1 }
b.ts
1 2 3 4 import {V} from '../observer/index' console .log (V);
简化命名空间 1 2 3 4 5 6 7 8 9 namespace A { export namespace B { export const C = 1 } } import X = A.B .C console .log (X);
合并命名空间 重名的命名空间会合并
声明文件d.ts 当使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能。
1 2 3 4 5 6 7 declare var 声明全局变量declare function 声明全局方法declare class 声明全局类declare enum 声明全局枚举类型declare namespace 声明(含有子属性的)全局对象interface 和 type 声明全局类型 /// <reference /> 三斜线指令
例如我们有一个express 和 axios
发现express 报错了
让我们去下载他的声明文件
npm install @types/node -D
那为什么axios 没有报错
我们可以去node_modules 下面去找axios 的package json
发现axios已经指定了声明文件 所以没有报错可以直接用
通过语法declare 暴露我们声明的axios 对象
declare const axios: AxiosStatic;
如果有一些第三方包确实没有声明文件我们可以自己去定义
名称.d.ts
创建一个文件去声明
例如express.d.ts
declare const express: ()=> any;
关于这些第三发的声明文件包都收录到了 npm
Mixins混入 对象混入 可以使用es6的Object.assign 合并多个对象
此时 people 会被推断成一个交差类型 Name & Age & sex;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 interface Name { name : string } interface Age { age : number } interface Sex { sex : number } let people1 : Name = { name : "小满" }let people2 : Age = { age : 20 }let people3 : Sex = { sex : 1 }const people = Object .assign (people1,people2,people3)
类的混入 首先声明两个mixins类 (严格模式要关闭不然编译不过)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class A { type : boolean = false ; changeType ( ) { this .type = !this .type } } class B { name : string = '张三' ; getName (): string { return this .name ; } }
下面创建一个类,结合了这两个mixins
首先应该注意到的是,没使用extends而是使用implements。 把类当成了接口
我们可以这么做来达到目的,为将要mixin进来的属性方法创建出占位属性。 这告诉编译器这些成员在运行时是可用的。 这样就能使用mixin带来的便利,虽说需要提前定义一些占位属性
1 2 3 4 5 6 class C implements A,B{ type :boolean changeType :()=> void ; name : string ; getName :()=> string }
最后,创建这个帮助函数,帮我们做混入操作。 它会遍历mixins上的所有属性,并复制到目标上去,把之前的占位属性替换成真正的实现代码
Object.getOwnPropertyNames()可以获取对象自身的属性,除去他继承来的属性,对它所有的属性遍历,它是一个数组,遍历一下它所有的属性名
1 2 3 4 5 6 7 8 Mixins (C, [A, B])function Mixins (curCls: any , itemCls: any [] ) { itemCls.forEach (item => { Object .getOwnPropertyNames (item.prototype ).forEach (name => { curCls.prototype [name] = item.prototype [name] }) }) }
Rollup & webpack构建TS项目 Rollup构建TS项目
安装依赖
全局安装rollup npm install rollup-g
安装TypeScript npm install typescript -D
安装TypeScript 转换器 npm install rollup-plugin-typescript2 -D
安装代码压缩插件 npm install rollup-plugin-terser -D
安装rollupweb服务 npm install rollup-plugin-serve -D
安装热更新 npm install rollup-plugin-livereload -D
引入外部依赖 npm install rollup-plugin-node-resolve -D
安装配置环境变量用来区分本地和生产 npm install cross-env -D
替换环境变量给浏览器使用 npm install rollup-plugin-replace -D
webpack构建TS项目
安装依赖
安装webpack npm install webpack -D
webpack4以上需要 npm install webpack-cli -D
编译TS npm install ts-loader -D
TS环境 npm install typescript -D
热更新服务 npm install webpack-dev-server -D
HTML模板 npm install html-webpack-plugin -D
tsconfig.json配置文件 这个文件是通过tsc --init
命令生成的
配置详情
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 "compilerOptions" : { "incremental" : true , "tsBuildInfoFile" : "./buildFile" , "diagnostics" : true , "target" : "ES5" , "module" : "CommonJS" , "outFile" : "./app.js" , "lib" : ["DOM" , "ES2015" , "ScriptHost" , "ES2019.Array" ], "allowJS" : true , "checkJs" : true , "outDir" : "./dist" , "rootDir" : "./" , "declaration" : true , "declarationDir" : "./file" , "emitDeclarationOnly" : true , "sourceMap" : true , "inlineSourceMap" : true , "declarationMap" : true , "typeRoots" : [], "types" : [], "removeComments" :true , "noEmit" : true , "noEmitOnError" : true , "noEmitHelpers" : true , "importHelpers" : true , "downlevelIteration" : true , "strict" : true , "alwaysStrict" : true , "noImplicitAny" : true , "strictNullChecks" : true , "strictFunctionTypes" : true , "strictPropertyInitialization" : true , "strictBindCallApply" : true , "noImplicitThis" : true , "noUnusedLocals" : true , "noUnusedParameters" : true , "noFallthroughCasesInSwitch" : true , "noImplicitReturns" : true , "esModuleInterop" : true , "allowUmdGlobalAccess" : true , "moduleResolution" : "node" , "baseUrl" : "./" , "paths" : { "jquery" : ["node_modules/jquery/dist/jquery.min.js" ] }, "rootDirs" : ["src" ,"out" ], "listEmittedFiles" : true , "listFiles" : true } "include" : [ "src/**/*" ], "exclude" : [ "demo.ts" ], "files" : [ "demo.ts" ]
介绍几个常用的:
include 指定编译文件默认是编译当前目录下所有的ts文件
exclude 指定排除的文件
target 指定编译js 的版本例如es5 es6
allowJS 是否允许编译js文件
removeComments 是否在编译过程中删除文件中的注释
rootDir 编译文件的目录
outDir 输出的目录
sourceMap 代码源文件
strict 严格模式
module 默认common.js 可选es6模式 amd umd 等
笔记内容来自CSDN小满ZS老师,更多进阶内容请查看下方链接
https://so.csdn.net/so/search?q=typescript&t=blog&u=qq1195566313&s=new