TypeScript是什么 
TypeScript开发环境搭建 
全局安装typescript: 
 
1 npm install typescript -g 
 
查看typescript当前版本号: 
 
 
将TS编译成JS( TS 不能直接在浏览器执行,需要编译器将TS转为JS) 
 
 
基础数据类型 
基础类型:Number、String、Boolean、null、undefined以及 ES6 的 Symbol  和 ES10 的 BigInt 。 
 
字符串类型 1 2 3 4 5 6 7 8 let  str : string  = "这是字符串类型" ;let  str1 : string  = 666 ;let  muban : string  = `web${str} ` ;
 
数字类型 支持十六进制、十进制、八进制和二进制 
1 2 3 4 5 6 7 let  num : number  = 123 ;let  notANumber : number  = NaN ;let  infinityNumber : number  = Infinity ;let  decimal : number  = 6 ;let  hex : number  = 0xf00d ;let  binary : number  = 0b1010 ;let  octal : number  = 0o744 ;
 
布尔类型 1 2 3 let  b :boolean  = false ;let  b2 :boolean  = Boolean (1 ); console .log (`b:${b} ,b2:${b2} ` ); 
 
空值类型 
JavaScript 没有空值(Void)的概念,在 TypeScript 中,可以用 void 表示没有任何返回值的函数
 
1 2 3 4 5 6 7 8 9 10 function  fnVoid ( ): void  {    console .log ("test void" );     return ;       } function  fnVoid2 ( ): void  {    return  123 ;      } 
 
void 类型的用法,主要是用在我们不希望 调用者关心函数返回值的情况下,比如通常的异步回调函数 
 
void也可以定义undefined 和 null类型 
1 2 let  u : void  = undefined let  n : void  = null ;
 
TIPS: 
如果你配置了tsconfig.json 开启了严格模式: 则 null 不能 赋予 void 类型 
1 2 3 4 5 {     "compilerOptions" :{         "strict" : true      } } 
 
解决方法: 
tsc --init创建tsconfig文件; 
tsconfig.json文件内搜索strict,值改为false; 
 
Null和undefined类型 1 2 let  u : undefined  = undefined ;let  n : null  = null ;
 
void 和 undefined 和 null 最大的区别 
void的内容也是不能去赋值给别人的
 
1 2 3 4 5 6 let  u : void  = undefined ;let  n : null  = null ;let  str : string  = "123" ;str = u; 
 
下面这样undefined与null可以赋值
 
1 2 3 4 5 let  u : undefined  = undefined ;let  n : null  = null ;let  str : string  = "123" ;str = u; 
 
NodeJs 环境执行TS 
上面每次执行代码,都需要将TS编译成JS,然后再通过NodeJs来执行JS,有点繁琐。
 
NodeJs直接运行TS需要安装两个依赖:
npm install @types/node -D(node环境支持的依赖必装) 
npm install ts-node -g 
输出版本号:ts-node -v 
NodeJs执行TS:ts-node xxx.ts 
 
Any 类型 和 unknown 顶级类型 
any与unknown没有强制限定哪种类型,可以定义任何类型的值,被称为顶级类型(top type)。
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 let  anys : any ;anys = true ;              anys = 18 ;                anys = "Hello World" ;     anys = [];                anys = {};                anys = null ;              anys = undefined ;         anys = Symbol ("type" );    let  value : unknown ;value = true ;              value = 18 ;                value = "Hello World" ;     value = [];                value = {};                value = null ;              value = undefined ;         value = Symbol ("type" );    
 
any与unknow区别 
TypeScript 3.0中引入的 unknown 类型也被认为是 top type ,但它更安全。与 any 一样,所有类型都可以分配给unknown
unknow类型比any更加严格当你要使用any 的时候可以尝试使用unknow
 
unknown可赋值对象只有unknown 和 any 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 let  names : unknown  = '123' ;let  names2 : string  = names;  let  ages : any  = 123 ;let  ages2 : string  = ages;let  aaa : unknown  = '123' ;let  bbb : unknown  = '456' ;let  ccc : any  = "789" ;aaa = bbb; aaa = ccc; 
 
unknow 不能调用属性和方法 
 
1 2 3 4 5 6 7 8 9 let  obj : any  = { b : 1  };obj.a ; let  obj2 : unknown  = { b : 1 , ccc : (): number  =>  213  };obj2.b ;   obj2.ccc ();  
 
声明变量的时候没有指定任意类型默认为any(如果使用any 就失去了TS类型检测的作用) 
 
接口和对象类型 interface定义对象类型 
在JS中,我们声明对象,直接写就好了
 
1 2 3 4 let  obj = {    name : "fsllala" ,     age : 18  } 
 
在TS中,我们定义对象的方式要用关键字interface (接口),我的理解是使用interface 来定义一种约束(类型),让数据的结构满足约束的格式。定义方式如下:
 
使用接口约束的时候不能多一个属性也不能少一个属性,必须与接口保持一致 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 interface  Person {    name :string ,     age :number  } const  person :Person ={    name :"fsllala"    } 
 
重名interface  可以合并 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 interface  A {    name : string  } interface  A {    age : number  } let  obj : A = {    name : "fsllala" ,     age : 18  }; console .log (obj); 
 
可选属性 使用?操作符 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 interface  Person  {    name : string ,     age?: number  } const  person : Person  = {    name : "fsllala"  } const  person2 : Person  = {    name : "fsl" ,     age : 18  } 
 
索引签名[propName: string] 
 
后端给我们返回的字段不确定,类型也不确定的时候可以用任意属性;
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 interface  Person  {    name : string ,     age : number ,     [propName : string ]: any  } const  person : Person  = {    name : "fsl" ,     age : 18 ,     ccc : 123 ,     ddd :'456' , } 
 
只读属性 readonly 
 
readonly 只读属性是不允许被赋值的只能读取;(跟input的readonly属性类似);
常用于函数和后台返回的数据ID
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 interface  Person  {    readonly  id : number      name : string ,     age : number ,     [propName : string ]: any ,     readonly  cb : () =>  boolean  } const  person : Person  = {    id : 2 ,     name : "fsl" ,     age : 18 ,     ccc : 123 ,     cb : () =>  {         return  false      } } person.id  = 3 ;   
 
添加函数 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 interface  Person  {    name : string ,     readonly  age : number ,     [propName : string ]: any ,     cb (): number ,      foo : () =>  boolean    } const  person : Person  = {    name : "fsl" ,     age : 18 ,     ccc : 123 ,     dd : 111 ,     cb : () =>  {         return  456      },     foo : () =>  {         return  false      } } 
 
继承 
 
和ES6中类的继承类似;
 
1 2 3 4 5 6 7 8 9 10 11 12 interface  A {    name : string  } interface  B extends  A {    age : number  } let  obj : B = {    name : "fsllala" ,     age : 18  }; 
 
interface定义函数类型 1 2 3 4 5 6 7 8 9 10 interface  Fn  {         (name : string ): number [] } const  foo : Fn  = function  (name: string  ) {    return  [1 , 2 , 3 , 4 ] } 
 
数组类型 
数组类型有多种声明方法:
 
普通方式:类型[ ] 
 
1 2 3 4 let  arr : number [] = [1 , 2 , 3 ];  let  arr2 : string [] = ["1" , "2" , "3" ];  let  arr3 : boolean [] = [true , false ];let  arr4 : any [] = [1 , "2" , true ,[],{}]; 
 
数组泛型 :Array<类型> 
 
1 2 3 4 let  arr : Array <number > = [1 , 2 , 3 ];  let  arr2 : Array <string > = ["1" , "2" , "3" ];  let  arr3 : Array <boolean > = [true , false ];let  arr4 : Array <any > = [1 , "2" , true , [], {}]; 
 
用接口表示数组:一般用来描述类数组 
 
1 2 3 4 5 6 interface  NumArray  {    [index : number ]: number  } let  arr : NumArray  = [1 , 2 , 3 ];
 
对象数组 
使用interface方式来定义对象数组
 
1 2 3 4 5 6 interface  X {    name : string ,     age?: number  } const  arr1 : X[] = [{ name : "fsllala" , age : 18  }, { name : "fsl"  }];
 
多维数组 1 2 3 4 5 6 let  arr : number [][] = [[1 , 2 ], [3 , 4 ]]; let  arr2 : number [][][] = [[[1 ]], [[2 ]]];let  arr3 : Array <Array <number >> = [[1 , 2 ], [3 , 4 ]]; let  arr4 : Array <Array <Array <number |string >>> = [[[1 ]], [[2 ,"lala" ]]];
 
arguments类数组 
函数内置的arguments,是个类数组,其实就是有length属性的对象;所以没有数组的方法:push、pop…
 
1 2 3 4 5 6 function  Arr (...args: any  ): void  {    console .log (arguments );      console .log (args);  } Arr (2 , 3 , 4 );
 
所以就会导致如下情况:
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function  Arr (...args: any  ): void  {         let  arr : number [] = arguments ;      let  arr2 : number [] = args;           let  arr3 :IArguments =arguments ;  } Arr (2 , 3 , 4 );  interface  IArguments  {[index : number ]: any ; length : number ;callee : Function ;} 
 
函数拓展 
匿名函数可以进行类型推导,不推荐在写类型,因为可能会写错; 
 
1 2 3 4 5 6 const  arr1 = ["lala" , "wawa" , "miaomiao" ];arr1.forEach ((item, index ) =>  {     console .log (item, index); }) 
 
interface定义函数类型; 
 
1 2 3 4 5 6 7 8 9 interface  Ikun  {    (name : string ): string  } const  kunkun : Ikun  = (aa : string ): string  =>  {    return  aa; } kunkun ("篮球" );
 
函数的调用签名(从对象的角度看待这个函数,也可以有其他属性); 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 interface  IBar  {    names : string ,     age : number ,     (num : number ): number  } const  bar2 : IBar  = (arg : number ): number  =>  {    return  arg; } bar2.names  = "fsllala" ; bar2.age  = 18 ; console .log (bar2 (222 ))
 
type定义函数类型; 
 
1 2 3 4 5 6 7 8 type  Bar  = (num1: number  ) =>  number ;const  bar : Bar  = (arg : number ): number  =>  {    return  arg; } console .log (bar (111 ));  
 
参数不能多传,也不能少传 必须按照约定的类型来 
 
1 2 3 4 5 6 7 const  fn = function  (name: string , age: number  ): string  {    return  name + age; } let  result = fn ("fsllala" , 18 );console .log (result); 
 
少传参数:定义默认的参数 
 
1 2 3 4 5 6 7 const  fn = function  (name: string , age: number  = 24  ): string  {    return  name + age; } let  result = fn ("fsllala" );console .log (result); 
 
可选属性 使用?操作符(不传默认为undefined) 
 
1 2 3 4 5 6 7 const  fn = function  (name: string , age?: number  ): string  {    return  name + age; } let  result = fn ("fsllala" );console .log (result); 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 interface  User  {    name : string ,     age : number  } const  fn = function  (user: User ): User  {    return  user; } let  result = fn ({    name : "fsllala" ,     age : 18  }) console .log (result); 
 
函数重载:方法名字相同,而参数不同,与返回值无关。
如果参数类型不同,则参数类型应设置为 any 。
参数数量不同你可以将不同的参数设置为可选。
 
1 2 3 4 5 6 7 8 9 10 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 )
 
Tip:JS好像是不能这样写的,JS重载是通过函数内部的arguments的长度来实现的;
 
类型断言 | 联合类型 | 交叉类型 联合类型 
可以是多种类型,中间用|隔开
 
1 2 3 4 5 6 7 let  myPhone : number  | string   = '010-820'     let  myPhone2 : number  | string   = true 
 
函数使用联合类型
1 2 3 4 5 6 7 8 const  fn1 = (types :number  | boolean ):boolean  =>  {    return  !!types } const  result =fn1 (1 );const  result2 = fn1 (false );console .log (result); console .log (result2); 
 
交叉类型 
类似于extends
多种类型的集合,联合对象将具有所联合类型的所有成员,中间用&隔开;
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 interface  People  {    age : number ,     height : number  } interface  Man  {    sex : string  } const  fsllala  = (man: People & Man ) => {    console .log (man.age )     console .log (man.height )     console .log (man.sex ) } fsllala ({    age : 18 ,     height : 173 ,     sex : 'male'  }); 
 
类型断言 
在使用联合类型的时候,可能会遇到某个属性A类型没有,B类型有,比如length属性number没有,string有;
 
1 2 3 4 5 let  fn1 = function (params:number |string  ):void {    console .log (params.length );   } fn1 ("123456" );
 
这个时候就得用到类型断言:需要注意的是,类型断言只能够「欺骗」TypeScript 编译器,无法避免运行时的错误,反而滥用类型断言可能会导致运行时错误:
 
1 值 as  类型  或  <类型>值  value as  string   <string >value 
 
1 2 3 4 5 6 let  fn1 = function  (params: number  | string  ): void  {    console .log ((params as  string ).length ); } fn1 ("123456" ); fn1 (123456 ); 
 
使用any临时断言  
1 2 (window  as  any ).abc  = 123  
 
内置对象 
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 ('lala~' )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 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 121 122 123 124 125 126 127 128 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 ) {     }); 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是推断不出来返回的是什么类型
1 2 3 4 5 function  promise ( ){    return  new  Promise ((resolve, reject ) =>  {         resolve (1 )     }) } 
 
指定返回的类型
 1 2 3 4 5 function  promise ( ){    return  new  Promise <number >((resolve, reject ) =>  {         resolve (1 )     }) } 
 
 函数定义返回promise 语法规则:Promise<T>
1 2 3 4 5 6 7 8 9 function  promise ( ): Promise <number > {      return  new  Promise <number >((resolve, reject ) =>  {         resolve (1 )     }) } promise ().then (res  =>  {    console .log (res);   }) 
 
Class类 
ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。基本上,ES6的class可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。详见:面向对象 
 
定义 在TypeScript是不允许直接在constructor 定义变量的
1 2 3 4 5 6 7 8 9 10 class  Person  {    constructor (name: string , age: number , sub: boolean  ) {                  this .name11  = name;         this .age11  = age;         this .sub11  = sub;     } } const  person = new  Person ("fsllala" , 18 , false );
 
 需要在constructor上面先声明
1 2 3 4 5 6 7 8 9 10 11 12 13 class  Person  {    name11 :string      age11 :number      sub11 :boolean      constructor (name: string , age: number , sub: boolean  ) {                  this .name11  = name;         this .age11  = age;         this .sub11  = sub;     } } const  person = new  Person ("fsllala" , 18 , false );
 
类的修饰符 
 总共有三个:public private protected
 
public(class默认):class定义的属性或方法内部外部都能访问 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class  Person  {    public  name11 : string      age11 : number      sub11 : boolean      constructor (name: string , age: number , sub: boolean  ) {                  this .name11  = name;         this .age11  = age;         this .sub11  = sub;     } } const  person = new  Person ("fsllala" , 18 , false );console .log (person.name11 );  console .log (person.age11 ); 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class  Person  {    public  name11 : string      private  age11 : number      sub11 : boolean      constructor (name: string , age: number , sub: boolean  ) {                  this .name11  = name;         this .age11  = age;         this .sub11  = sub;     } } const  person = new  Person ("fsllala" , 18 , false );console .log (person.name11 );  console .log (person.age11 ); 
 
protected:只能在内部和继承的子类中访问 不能在外部访问 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class  Person  {    public  name11 : string      private  age11 : number      protected  sub11 : boolean      constructor (name: string , age: number , sub: boolean  ) {                  this .name11  = name;         this .age11  = age;         this .sub11  = sub;     } } class  Man  extends  Person {    constructor ( ){         super ("fsllala" , 18 , false );         console .log (this .name11 );         console .log (this .age11 );           console .log (this .sub11 );               } } 
 
static 静态属性 和 静态方法 
静态方法中的this指向类本身,非静态方法的this指向实例对象;
即:静态方法中的this,只能调用static定义的属性或方法;
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class  Person  {    public  name11 : string      private  age11 : number      protected  sub11 : boolean      static  aaa :string ="静态属性直接赋值" ;     constructor (name: string , age: number , sub: boolean  ) {                  this .name11  = name;         this .age11  = age;         this .sub11  = sub;     }     static  run ():string {                  this .aaa ;          return  "静态方法中的this指向对象本身"      } } console .log (Person .aaa );console .log (Person .run ());
 
interface 定义类 
TS interface 定义类,使用关键字 implements ;后面跟interface的名字,多个用逗号隔开;继承还是用extends;
与C#或Java里接口的基本作用一样,TypeScript也能够用它来明确的强制一个类去符合某种契约。
extends可以接口继承接口,可以类继承类;implements是类实现接口;
 
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 interface  PersonClass  {    get (type : boolean ): boolean  } interface  PersonClass2  {    set (): void ,     asd : string  } class  A  {    name : string      constructor ( ) {         this .name  = "123"      } } class  Person  extends  A  implements  PersonClass , PersonClass2  {    asd : string      constructor ( ) {         super ()         this .asd  = '123'      }     get (type : boolean  ) {         return  type      }     set ( ) {     } } 
 
抽象类 
应用场景:如果你写的类实例化之后毫无用处此时我可以把他定义为抽象类
或者你也可以把他作为一个基类-> 通过继承一个派生类去实现基类的一些方法
 
1 2 3 4 5 6 abstract  class  A  {   public  name :string      }   new  A ()
 
我们在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 25 abstract  class  A  {    name : string      constructor (name: string  ) {         this .name  = name;     }          setName (name: string  ) {         this .name  = name;     }          abstract  getName (): string  } class  B  extends  A  {    constructor ( ) {         super ('lala' )     }     getName (): string  {         return  this .name      } } let  b = new  B ();b.setName ("haha~" ) 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 4 let  arr :[number ,string ] = [1 ,'string' ];arr.push (boolean );  arr.push (1 ); 
 
应用场景 例如定义excel返回的数据
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 6 7 8 9 enum  Color  {    Red ,     Green ,     Blue , } console .log (Color .Red ); console .log (Color .Green ); console .log (Color .Blue ); 
 
这样写就可以实现应为ts定义的枚举中的每一个组员默认都是从0开始的所以也就是
1 2 3 4 5 6 7 8 9 10 enum  Color  {    Red  = 0 ,     Green  = 1 ,     Blue  = 2 , } console .log (Color .Red ); console .log (Color .Green ); console .log (Color .Blue ); 
 
增长枚举
1 2 3 4 5 6 7 8 9 enum  Color  {    Red  = 5 ,     Green ,     Blue , } console .log (Color .Red ); console .log (Color .Green ); console .log (Color .Blue ); 
 
自定义枚举
1 2 3 4 5 6 7 8 9 enum  Color  {    Red  = 5 ,     Green  = 13 ,     Blue  = 18 , } console .log (Color .Red ); console .log (Color .Green ); console .log (Color .Blue ); 
 
字符串枚举 1 2 3 4 5 6 7 8 9 enum  Color {    Red  = 'red' ,     Green  = 'green' ,     Blue  = 'blue'   } console .log (Color .Red ); console .log (Color .Green ); console .log (Color .Blue ); 
 
异构枚举 枚举可以混合字符串和数字成员
1 2 3 4 enum  Color {    No  = "No" ,     Yes  = 1 ,  } 
 
接口枚举 定义一个枚举Color 定义一个接口AA 他有一个属性red 值为Color.Yes
声明对象的时候要遵循这个规则
1 2 3 4 5 6 7 8 9 10 11 12 13 14 enum  Color  {    No  = "No" ,     Yes  = 1 , } interface  AA {    red : Color .Yes  } let  obj1 : AA  = {              red : 1  } 
 
const枚举 
大多数情况下,枚举是十分有效的方案。 然而在某些情况下需求很严格。 为了避免在额外生成的代码上的开销和额外的非直接的对枚举成员的访问,我们可以使用 const枚举。 常量枚举通过在枚举上使用 const修饰符来定义
 
let 和 var 都是不允许声明enum的,只能使用const声明 
const 声明的枚举会被编译成常量 
普通声明的枚举编译完后是个对象 
 
普通声明编译之后 
 
1 2 3 4 5 6 7 8 9 enum  Color  {    Yes ,     No , } let  code : number  = 0 ;if  (code === Color .No ) {} 
 
JS:
1 2 3 4 5 6 7 8 var  Color ;(function  (Color ) {     Color [Color ["Yes" ] = 0 ] = "Yes" ;     Color [Color ["No" ] = 1 ] = "No" ; })(Color  || (Color  = {})); var  code = 0 ;if  (code === Color .No ) {} 
 
const声明编译之后 
 
1 2 3 4 5 6 7 8 9 const  enum  Color  {    Yes ,     No , } let  code : number  = 0 ;if  (code === Color .No ) {} 
 
JS:
1 2 3 var  code = 0 ;if  (code === 1  ) {} 
 
反向映射 
它包含了正向映射( name -> value)和反向映射( value -> name) 
要注意的是 不会 为字符串枚举成员生成反向映射。 
 
1 2 3 4 5 6 7 enum  Enum  {    success } let  result : number  = Enum .success ;console .log (result); let  result2 = Enum [result];console .log (result2); 
 
类型推论|类型别名 类型推论 
我声明了一个变量但是没有定义类型
TypeScript 会在没有明确的指定类型的时候推测出一个类型,这就是类型推论
 
1 2 3 let  str = "fsllala" ;str = 18 ;   
 
如果你声明变量没有定义类型也没有赋值这时候 TS 会推断成 any 类型可以进行任何操作
1 2 3 4 5 let  strstr = 123  str = "马杀鸡"  str = false  str = [] 
 
类型别名 
type 关键字(可以给一个类型定义一个名字)多用于复合类型
 
1 2 3 4 type  s = string ;let  str : s = "fsllala" ;console .log (str); 
 
1 2 3 type  s = string |number let  str :s = "永恒的紫罗兰花园" let  num :s = 520 
 
1 2 3 4 type  s = () =>  string let  str : s = () =>  "fsllala" ;console .log (str ()); 
 
1 2 3 4 5 type  value = boolean  | 0  | '213' let  s : value = "213" ;let  s2 : value = "111" ; 
 
never类型 
TypeScript 将使用 never 类型来表示不应该存在的状态,也就是值永不存在的类型。
 
值会永不存在的两种情况:
如果一个函数执行时抛出了异常 ,那么这个函数永远不存在返回值(因为抛出异常会直接中断程序运行,这使得程序运行不到返回值那一步,即具有不可达的终点,也就永不存在返回了); 
数中执行无限循环的代码(死循环 ),使得程序永远无法运行到函数返回值那一步,永不存在返回。 
 
 
 
1 2 3 4 5 6 7 8 9 10 11 12   function  error (message: string  ): never  {    throw  new  Error (message); }   function  loop ( ): never  {    while  (true ) {     } } 
 
举一个我们可能会见到的例子:
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 interface  Foo  {    type : "保安"  } interface  Bar  {    type : "草莓"  } type  All  = Foo  | Bar function  handleValue (val: All ) {    switch  (val.type ) {         case  '保安' :                          break          case  '草莓' :                          break          default :                                       const  exhaustiveCheck : never  = val             break      } } handleValue ({ type : "草莓"  });
 
比如新来了一个同事他新增了一个C接口,我们必须手动找到所有 switch 代码并处理,否则将有可能引入 BUG 。
 
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 interface  Foo  {    type : "保安"  } interface  Bar  {    type : "草莓"  } interface  C {    type : "卷心菜"  } type  All  = Foo  | Bar  | Cfunction  handleValue (val: All ) {    switch  (val.type ) {         case  '保安' :                          break          case  '草莓' :                          break          default :                          const  exhaustiveCheck : never  = val;               break      } } handleValue ({ type : "草莓"  });
 
所以通过这个办法,你可以确保 handleValue 总是穷尽 (exhaust) 了所有 All 的可能类型。
 
symbol类型 
ES6 引入了一种新的基本数据类型Symbol,表示独一无二的值;
内存地址的指针位置不同,所以是唯一值;
 
1 2 3 4 5 6 7 8 9 10 11 let  name1 : symbol  = Symbol ("fsllala" );let  name2 : symbol  = Symbol ("fsllala" );let  age :symbol =Symbol (18 );console .log (name1 === name2);  
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 let  name1 : symbol  = Symbol ("fsllala" );let  name2 : symbol  = Symbol ("fsllala" );let  age : symbol  = Symbol (18 );let  obj1 = {    [name1]: "forward" ,     [age]: 24 ,     sex : 1 ,     height : 173 , } for  (let  i in  obj1) {    console .log (i);  } console .log (Object .keys (obj1));  console .log (Object .getOwnPropertyNames (obj1));  
 
静态方法 Reflect.ownKeys() 返回一个由目标对象自身的属性键组成的数组(Array)。
语法:Reflect.ownKeys(target) => target 获取自身属性键的目标对象。
Reflect.ownKeys 方法返回一个由目标对象自身的属性键组成的数组 。它的返回值等同于 Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target) ) 。
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 let  name1 : symbol  = Symbol ("fsllala" );let  name2 : symbol  = Symbol ("fsllala" );let  age : symbol  = Symbol (18 );let  obj1 = {    [name1]: "forward" ,     [age]: 24 ,     sex : 1 ,     height : 173 , } console .log (Object .getOwnPropertySymbols (obj1)); console .log (Reflect .ownKeys (obj1)); 
 
Symbol.iterator 迭代器 和 生成器 for of 
一般来说Object对象是不能通过for…of来进行遍历的; 
 
1 2 3 4 5 6 7 8 let  obj1 = {    name :"fsllala" ,     age :18 ,     sex :1  } for (let  i of  obj1); 
 
可以给Object对象提供一个Iterator方法,使对象也能使用for…of遍历; 
 
要知道js的迭代器,我们就要先知道迭代的意思,实际上迭代的本意是遍历,随着不断有新的数据类型加入,我们就要用不同的for语句去循环,这就显得很麻烦,所以就有了迭代的概念 
所有数据类型的遍历都遵循的一个协议。所以以后你对遵循了迭代协议的数据类型 你只需要用迭代去遍历就可以了。顺便一提:for…of是用迭代器来实现的,只要你能用for…of来遍历的数据都是实现了迭代协议的数据
string,array,map,set,arguments,Nodelist等dom元素 ;注意注意;没有object  
for…of 会遍历可迭代的对象,调用对象上的 Symbol.iterator 方法。(此对象非彼对象,这个对 象是指你即将下手的目标)
对象也是不支持的,因为对象没用 Symbol.iterator 方法。
 
迭代器 
迭代器Iterator 的用法
Iterator 是 es6 引入的一种新的遍历机制 ,两个核心:
迭代器是一个统一的接口,它的作用是使各种 数据结构 可被便捷的访问,它是通过一个键为 Symbol.iterator 的方法来实现。 
迭代器是用于 遍历 数据结构元素的指针(如数据库中的游标)。 
 
 
使用迭代:
实现的迭代协议的数据类型,里面都会有一个 [Symbol.iterator]方法 
进行迭代的时候用迭代器的next来取值,这个next返回的是一个对象:{value:value,done:"是否完成遍历"} 
当 value是underfined 、done 为 true 时则遍历结束 
 
 
实现的迭代协议的数据类型:
string、array、map、set、arguments、Nodelist等dom元素;注意注意;没有object  
 
 
 
1 2 3 4 5 6 7 8 9 const  str : string  = "fsl" ;const  iterator : Iterator <string > = str[Symbol .iterator ]();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 let  arr : Array <number > = [1 , 5 , 6 ]; let  iterator : Iterator <number > = arr[Symbol .iterator ]()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 let  arr : Array <number  | string > = ["泛型" , "实现简单的迭代器" ];let  set : Set <number > = new  Set ([1 , 2 , 3 , 4 ]);   function  iteratorFun (args: any  ): void  {     const  it : Iterator <any > = args[Symbol .iterator ]();     let  next : any  = { done : false  };     while  (!next.done ) {          next = it.next ();          if  (!next.done ) {             console .log (next);         }     } } iteratorFun (arr);iteratorFun (set);
 
泛型 
泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候在指定类型的一种特性
 
函数泛型 我写了两个函数一个是数字类型的函数,另一个是字符串类型的函数,其实就是类型不同,实现的功能是一样的,这时候我们就可以使用泛型来优化。
1 2 3 4 5 6 7 8 9 10 function  num (a: number , b: number  ): Array <number > {    return  [a, b]; } function  str (a: string , b: string  ): Array <string > {    return  [a, b]; } console .log (num (1 , 2 ));  console .log (str ('fsllala' , '18' )); 
 
语法为函数名字后面跟一个<参数名> 参数名可以随便写 例如我这儿写了T;
当我们使用这个函数的时候把参数的类型传进去就可以了 (也就是动态类型);
即:定义这个函数的时候,不定义参数的类型,而是让调用者告知我这里的参数是什么类型;
 
1 2 3 4 5 6 7 8 9 10 function  add<T>(a : T, b : T): Array <T> {    return  [a, b]; } add<number >(1 ,2 ); add<string >("fsllala" ,'18' ); add (1 ,2 )add ('1' ,'2' )
 
我们也可以使用不同的泛型参数名,只要在数量上和使用方式上能对应上就可以
 
1 2 3 4 5 6 function  sub<T, U>(a : T, b : U): Array <T | U> {    let  arr : Array <T | U> = [a, b];     return  arr; } sub<number ,boolean >(66 ,true ); 
 
泛型接口 
声明接口的时候 在名字后面加一个 <参数>
使用的时候传递类型
 
1 2 3 4 5 6 7 8 9 10 11 interface  IKun <T> {    name : T,     age : number ,     hobby : T[] } const  kunkun : IKun <string > = {    name : "lala" ,     age : 18 ,     hobby : ["唱" , "跳" , "rap" , "篮球" ] } 
 
1 2 3 4 5 6 7 8 9 10 11 12 interface  IKun <T = string > {    name : T,     age : number ,     hobby : T[] } const  kunkun : IKun  = {    name : "lala" ,     age : 18 ,     hobby : ["唱" , "跳" , "rap" , "篮球" ] } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 interface  CreateArrayFunc <T> {    (length : number , value : T): Array <T> } let  createArrayFunc : CreateArrayFunc <string >;createArrayFunc = function  <T>(length : number , value : T): Array <T> {     let  result : T[] = [];     for  (let  i = 0 ; i < length; i++) {         result[i] = value;     }     return  result; } let  results = createArrayFunc (3 , "x" );console .log (results);  
 
泛型类 1 2 3 4 5 6 7 8 9 10 class  Point <T>{    x : T     y : T     constructor (x: T, y: T ) {         this .x  = x;         this .y  = y;     } } const  point1 = new  Point <number >(11 , 22 );const  point2 = new  Point <string >('11' , '22' );
 
泛型约束 1 2 3 4 function  getLength<T>(args :T){    return  args.length ;  } 
 
1 2 3 4 5 6 7 8 9 10 11 12 interface  Ilength  {    length : number  } function  getLength<T extends  Ilength >(args : T) {    return  args.length ; } getLength ("123" );getLength ([1 , 2 ]);getLength ({ length : 77  });
 
使用keyof 约束对象
平时在开发中我们可能会看到一些常用的名称:
T:Type的缩写,类型; 
K、V:key和value的缩写,键值对; 
E:Element的缩写,元素; 
O:Object的缩写,对象; 
 
 
 
下面场景不会报错:
1 2 3 4 5 6 7 function  prop<O>(obj : O, keys) {    return  obj[keys]; } let  info = { a : 1 , b : 2 , c : 3  };prop (info, "a" );console .log (prop (info, "d" ));  
 
解决方法:其中使用了TS泛型和泛型约束。使用extends关键字添加泛型约束,keyof操作符获取对象键的联合类型;
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 interface  IKun  {    name : string ,     age : number  } type  IKunKeys  = keyof IKun ; const  kunkun : IKunKeys  = "name" ;const  kunkun2 : IKunKeys  = "age" ;const  kunkun3 : IKunKeys  = "sex" ; 
 
如上问题的解决:
 
1 2 3 4 5 6 7 8 function  prop<O, K extends  keyof O>(obj : O, keys : K) {    return  obj[keys]; } let  info = { a : 1 , b : 2 , c : 3  };prop (info, "a" );console .log (prop (info, "d" ));  
 
参考文献 TS系列篇|泛型 
模块化 
先来看一个现象:不同TS模块下会产生命名冲突:
 
1 2 3 const  name1 = "fsllala123" ;console .log (name1);
 
1 2 3 const  name1="fsllala456" ;console .log (name1);
 
什么是模块化?
 
JavaScript 规范声明任何没有 export 的 JavaScript 文件都应该被认为是一个脚本,而非一个模块。在一个脚本文件中,变量和类型会被声明在共享的全局作用域。 
如果你有一个文件,现在没有任何 import 或者 export,但是你希望它被作为模块处理,添加这行代码; 这会把文件改成一个没有导出任何内容的模块,这个语法可以生效,无论你的模块目标是什么。 
 
 
ES Module 
TypeScript中最主要使用的模块化方案就是ES Module,也就是ES6的写法,详见文章模块化规范 ;
 
TS文件中,即使两个不同的TS文件,比如index.ts和index2.ts,命名同一个变量,也会起冲突。因为它的内容被视为全局可见的(因此对模块也是可见的)
 
TypeScript与ECMAScript 2015一样,任何包含顶级import或者export的文件都被当成一个模块。相反地,如果一个文件不带有顶级的import或者export声明,那么它的内容被视为全局可见的(因此对模块也是可见的)
 
ES6模块化 
解决全局变量冲突(每个文件添加export{}即可) 
 
1 2 3 4 const  name1 = "fsllala123" ;console .log (name1);export {}
 
1 2 3 4 const  name1="fsllala456" ;console .log (name1); export {}
 
1 2 3 const  name1 = "fsllala123" ;export  { name1 }
 
1 2 3 import  { name1 } from  "./index" console .log (name1); 
 
内置类型导入 1 2 3 4 5 6 7 8 export  interface  IKun  {    name : string ,     age : number ,     hobby : string [] } export  type  IPerson  = string  | number ;
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import  type  { IKun , IPerson  } from  "./type" ; const  person1 : IPerson  = "fsllala" ;const  kunkun : IKun  = {    name : "xiaoheizi" ,     age : 18 ,     hobby : ["唱" , "跳" , "rap" , "篮球" ] } console .log (kunkun);
 
这里需要注意的是:不使用type前缀,也可以导入类型。那么为啥要加上type前缀呢?
TS最终要被编译成JS代码,类型是没用的,通过语法识别TS/JS的成本要比直接引入的时候就用type表明了是类型的成本大,到时候类型部分的代码就直接删除了;
 
namespace命名空间 
namespace常规写法 
1 2 3 4 5 6 7 namespace  AA {    const  name1 = "fsllala" ;     const  age1 = 18 ; } console .log (AA ); 
 
1 2 3 4 5 6 namespace  AA {    export  const  name1 = "fsllala" ;     export  const  age1 = 18 ; } console .log (AA ); 
 
同一模块(不同模块)下有重名的namespace,里面属性会合并 
 
因为属性会合并,所以会出现以下情况:
 
1 2 3 4 5 6 7 8 9 10 namespace  AA {    export  const  name1 = "fsllala" ; } namespace  AA {    export  const  age1 = 18 ; } console .log (AA ); 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 namespace  AA {    export  const  name1 = "fsllala" ;       export  const  age1 = 18 ;   } namespace  AA {    export  const  name1 = "fsllala" ;       export  const  age1 = 18 ;  } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 namespace  AA {    export  var  name1 = "fsllala" ;      export  var  age1 = 18 ;  } namespace  AA {    export  var  name1 = "fsllala" ;      export  var  age1 = 18 ;  } console .log (AA ); 
 
嵌套命名空间 1 2 3 4 5 6 7 8 9 namespace  AA {    export  namespace  BB {         export  const  name1 = "fsllala" ;         export  const  age1 = 18 ;     } } console .log (AA ); 
 
抽离命名空间 1 2 3 4 5 6 7 8 export  namespace  AA {    export  namespace  BB {         export  const  name1 = "fsllala" ;         export  const  age1 = 18 ;     } } 
 
1 2 3 import  { AA  } from  "./index" console .log (AA );  
 
简化命名空间 
除了使用const还可以使用import来简化;
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import  { AA  } from  "./index" import  { AA  } from  "./index" const  method1 = AA .BB .name1 ;console .log (method1);  import  method2 = AA .BB .name1 ;console .log (`method2:${method2} ` ); 
 
in操作符 
如果指定的属性在指定的对象或其原型链中,则 in 运算符返回true;
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 interface  Fish  {    swim (): void  } interface  Dog  {    run : () =>  void  } function  move (animal: Fish | Dog ) {    if  ("swim"  in  animal) {         animal.swim ();      } else  {         animal.run ();     } } move ({    swim ( ) {         console .log ("fish is swiming~~" );     } }) 
 
三斜线指令 
重点:我们知道在 TS 项目中,文件之间相互引用是通过 import来实现的,那么声明文件之间的引用呢?没错通过三斜线指令 。
 
三斜线指令常用的就两个功能:
如果对比 import 的功能,我们可以写出如下的等式:
/// <reference path="..." /> == import filename.xxx 
/// <reference types="..." /> == import lodash from "lodash" 
 
PS:下方代码使用ts-node输出有有问题,暂未找到解决方法;
But 通过tsc --outFile sample.js index.ts将index.ts编译成sample.js方法可行
 
1 2 3 4 5 6 7 8 9 10 11 12 13 namespace  A {export  const  fn  = ( ) => 'a' } namespace  A {export  const  fn2  = ( ) => 'b' } console .log (A);
 
声明文件 
这里环境为:vite+vue3+ts;
 
我们之前编写的typescript文件都是 .ts 文件,这些文件最终会输出 .js 文件,也是我们通常编写代码的地方; 
还有另外一种文件 .d.ts 文件,它是用来做类型的声明(declare),称之为类型声明(Type Declaration)或者类型定义(Type Definition)文件。 
.d.ts文件是不需要导出的;让他直接在全局就ok; 
 
外部定义类型声明 – 第三方库 有一些第三方库是没有写自己的声明文件的,我们在引用的时候,会报错。以lodash库为例(lodash是有第三方写好的声明文件库的,这里我们自己写)。
安装第三方库 
 
 
在vue文件中进入第三方库,由于没有声明文件,所以会报错。 
 
手写声明文件 
 
这里新建一个d.ts文件,例如 fsllala.d.ts
1 2 3 declare  module  "lodash" ;
 
然后在lodash.vue中发现报错消失了,即可以使用第三方库了(如果还报错,重启VS Code即可);
但是还不知道模块里面有什么东西,所以使用的时候不会有提示。可以在模块内部作用域自定义函数,解决不提示的问题。 
 
1 2 3 4 5 6 declare  module  "lodash" {    export  function  max (...args:any [] ):any ;     export  function  mean (...args:any [] ):any ; } 
 
1 2 3 4 5 6 <script setup lang="ts" > import  _ from  "lodash" ;console .log (_.max ([4 , 2 , 8 , 6 ])); console .log (_.mean ([4 , 2 , 8 , 6 ])); </script> 
 
自己代码类型声明 
一般来说TS的类型是不需要单独抽离到d.ts文件中的。但是一些全局声明的变量/函数/类例外。 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 const  whyName = "Fsllala" ;const  whyAge = 18 ;const  whyHeight = 188 ;function  globalFunc (args ) {  return  `this is globalFunction~${args} ` ; } function  Person (name, age ) {  this .name  = name;   this .age  = age; } 
 
上面如果是JS,就可以直接引用了(把script标签中的 “lang=’ts’”去掉,就可以用了);显然是ts的问题;
1 2 3 4 5 6 7 8 9 10 11 12 declare  const  whyName : string ;declare  const  whyAge : number ;declare  const  whyHeight : number ;declare  function  globalFunc (args: string  ): string ;declare  class  Person  {    name : string      age : number      constructor (name: string , age: number  ) } 
 
然后在lodash.vue中发现报错消失了,即可以使用全局变量/函数/类了(如果还报错,重启VS Code即可);
Partial 
用于构造一个Type下面的所有属性都设置为可选的类型;
 
1 2 3 4 5 6 7 8 interface  IKun {    name :string ,     age :number ,     hobby :string [] } type  IKunOptional  = Partial <IKun >;
 
Record<Keys, Type> 
用于构造一个对象类型,它所有的key(键)都是Keys类型,它所有的value(值)都是Type类型。
 
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 interface  IKun  {    name : string ,     age : number ,     hobby?: string [] } type  t1 = "上海"  | "北京"  | "洛杉矶" ;type  IKuns  = Record <t1, IKun >;const  ikuns : IKuns  = {    "上海" : {         name : "xxx" ,         age : 18      },     "北京" : {         name : "xxx" ,         age : 18      },     "洛杉矶" : {         name : "xxx" ,         age : 18      }, }