TypeScript

環(huán)境搭建

  • npm i typescript -g
    • 只需要安裝一次
  • tsc --init
    • 會(huì)生成tsconfig.json文件
  • 打開配置文件中"outDir": "./",的注釋
    • 根據(jù)需求修改
  • tsc 文件名
    • 執(zhí)行編譯生成js文件
    • tsc --version 獲取版本號(hào)

VS半自動(dòng)化環(huán)境

  • 終端
  • 運(yùn)行任務(wù)
  • tsc 監(jiān)視...
    • 即可實(shí)現(xiàn)變化保存自動(dòng)編譯為js文件

也可以配置npm腳本實(shí)現(xiàn)

"build": "tsc",
"build:watch": "tsc --watch"

編譯指令

tsc 1.ts --outDir ./dist
如果不加--outDir則默認(rèn)會(huì)編譯到ts同一目錄
ts-node

各種規(guī)范(和ts無(wú)關(guān))

  • AMD CMD require.js sea.js 都基本上過(guò)時(shí)放祟,不需要關(guān)心
  • node commonjs commonjs2
  • es6 module
  • umd 兼容以上三種

tsconfig


"./src":只編譯src目錄下文件,內(nèi)部子文件夾不編譯

"./src//":代表遞歸編譯文件夾內(nèi)部所有子文件夾 后面代表所有文件

ts-node:其他類型編譯器 ts-node直接編譯


直接運(yùn)行

  • vscode按照coderunner插件
  • npm install ts-node -g
  • 運(yùn)行即可

ts數(shù)據(jù)類型


數(shù)字,字符串杈女,布爾值

null underfined
它們倆是其他類型的子類型挣惰,可以賦值給其他類型
例如:let name:string=null;

但是需要打開:"strictNullChecks": false, 否則報(bào)錯(cuò)

不然就只能let name:string|null=null;

數(shù)組 元組 枚舉

void any Never


類型系統(tǒng)


string number boolean 基本類型

String Number Boolean 對(duì)象類型


基本類型可以賦值給包裝類型腾降,但是反之不可

數(shù)組(必須存儲(chǔ)同一類型)

//基本語(yǔ)法
//數(shù)組的聲明翁都,此時(shí)push是沒用的潮罪,因?yàn)槲炊x
// let arr:number[];
//數(shù)組的定義
let arr:number[]=[];
//泛型方式
// let arr1:Array<number>;
arr.push(...[1,2,4])
console.log(arr)

元組(類型不必相同)

長(zhǎng)度和類型都確定的數(shù)組姨谷,而且后面數(shù)據(jù)和前面類型必須一一對(duì)應(yīng)

let data:[number,string,boolean];
data=[1,"a",true];
說(shuō)明:元組再3.1之后逗宁,不能越界使用聯(lián)合類型了,而且賦值和定義的類型要一一對(duì)應(yīng)

聯(lián)合類型

//多個(gè)類型中的一個(gè)  或的關(guān)系
let a:string|number|boolean=20;
a="a";
console.log(a)

枚舉

enum Color{
    RED,
    YELLOW
}
console.log(Color.RED);//0
console.log(Color.YELLOW);//1

enum Color{
    RED=1,
    YELLOW
}
console.log(Color.RED);//1
console.log(Color.YELLOW);//2


//可以修改某個(gè)值然后后續(xù)的值順延即可
enum Week{
    MONDAY=2,
    TUESDAY
}
console.log(Week.TUESDAY);//3
  • 常數(shù)枚舉

常數(shù)枚舉后續(xù)不可修改梦湘,所以在編譯成js時(shí)候直接輸出部分是0瞎颗,1數(shù)字而不是變量

const enum Colors{
    Red,
    Yellow
}
console.log(Colors.Red,Colors.Yellow); //0  1
  • 枚舉的兼容性

枚舉類型與數(shù)字類型兼容件甥,并且數(shù)字類型與枚舉類型兼容;不同枚舉類型之間是不兼容的


Never

其他類型的子類型

說(shuō)明:代表那些永遠(yuǎn)不存在的值的類型哼拔,ts也可以自動(dòng)推斷引有,never此時(shí)也可以省略

返回值是never的函數(shù),永遠(yuǎn)不能正常結(jié)束倦逐,必須是類
似于拋出錯(cuò)誤這種譬正,也就代表著永遠(yuǎn)沒有返回值,異常不會(huì)正常走返回
function err():never{
    throw new Error("error")
}

Any

說(shuō)明:任意類型,在不確定數(shù)據(jù)類型的情況下使用
let a:any="a";
a=10;
console.log(a)

類型綜合

/**
 * 數(shù)據(jù)類型:
 * 布爾類型(boolean)
 * 數(shù)字類型(number)
 * 字符串類型(string)
 * 元組類型(tuple)
 * 枚舉類型(enum)
 * 任意類型(any)
 * null和underfined
 * void類型
 * never類型:從不會(huì)出現(xiàn)的值
 */

 //不賦值檬姥,也不會(huì)有默認(rèn)值
let flag:boolean=true
//第一種定義數(shù)組的方式
let arrs:number[]=[1,2,3]
//第二種定義數(shù)組的方式
let arrs1:Array<number>=[1,2,3]
//第三種定義數(shù)組的方式
let arrs4:Array<any>=[1,'3',true] //不會(huì)報(bào)錯(cuò)

//元組類型:屬于數(shù)組的一種,此時(shí)數(shù)據(jù)類型和后面賦值要一一對(duì)應(yīng)
let arrs2:[number,string]=[123,'this is ts']

//枚舉類型
enum WEEK{
    success=1, //指定枚舉從1開始曾我,不指定則默認(rèn)0起始
    error,//此時(shí)不指定,則為2健民,如果多個(gè)值中間指定賦值抒巢,則后面的依此加一
    'underfined'=-1,
    'null'=-2
}
let w:WEEK=WEEK.error;
console.log(WEEK.underfined); //-1

//任意類型
let num:any=123;
num='asdas';

//任意類型使用場(chǎng)景
let item:any=document.getElementById('test');

//null和underfined是其他(never)數(shù)據(jù)類型的子類型
let num1:undefined;
// console.log(num1) //不報(bào)錯(cuò),如果定義為number類型則報(bào)錯(cuò)了

let num2:undefined|number;
// console.log(num2);//兼具兩者的優(yōu)勢(shì)


function run():void{

}
//聲明never的變量只能被never類型賦值:代表從不會(huì)出現(xiàn)的值
let a:never;
a=(()=>{
    throw new Error('錯(cuò)誤')
})()

函數(shù)

//函數(shù)表達(dá)式
let f:()=>string=function():string{
    return "a"
 }
  let f:()=>void=function(){
 }
//函數(shù)聲明
function fn(x:number,y:number):number{
    return x+y
}

type

type用來(lái)定義類型或者類型別名

type GetUserName = (firstName: string, lastName: string) => {name:string};
let getUserName: GetUserName = function (firstName: string, lastName: string): {name:string} {
    return {name:firstName+lastName};
}
  • 泛型類型別名(擴(kuò)展)
type Cart<T>={list:T[]}|T[]; //聯(lián)合類型
let c1:Cart<string>={list:['1']};
let c2:Cart<string>=['1']

可選參數(shù)和參數(shù)默認(rèn)值

說(shuō)明:通過(guò)?來(lái)定義可選參數(shù)
    function fn(x:Type,y?:Type):Type
    可選參數(shù)默認(rèn)為undefined
    可選參數(shù)必須在必傳參數(shù)之后
//可選參數(shù)
function fn(x:number,y?:number):number{
   return x+y
}
//參數(shù)默認(rèn)值秉犹,其實(shí)因?yàn)轭愋屯茖?dǎo)蛉谜,可直接寫成y=1
function fn1(x:number,y:number=1):number{
   return x+y
}
console.log(fn(1));//NaN
console.log(fn1(1));//2
補(bǔ)充:可選參數(shù)和默認(rèn)值不要用在一個(gè)參數(shù)上

剩余參數(shù)

//剩余參數(shù)
function fn2(...arg:any[]){
   console.log(arg) //[ 1, 2, 3 ]
}
fn2(1,2,3)


function sum(...numbers:Array<number>) {
    //accu是最終要返回的值
    return numbers.reduce((accu,item)=>accu+item,0);
}

函數(shù)重載

//注意:這三行除了注釋之外,必須緊緊的貼在一起凤优,否則報(bào)錯(cuò)

//定義函數(shù)的重載格式
function fn(x:number,y:string);
function fn(x:number,y:number);
//定義函數(shù)具體的實(shí)現(xiàn)
function fn(x:any,y:any){
   console.log(x+y)
}
fn(1,2) //3
fn(1,"2")//12
  • 函數(shù)參數(shù)的協(xié)變

不推薦這么使用悦陋,了解即可

type logFunc=(a:number|string)=>void;
let log:logFunc;
function log1(a:number|string|boolean) {
    
}
log=log1;//正確
//其實(shí)很好理解,ts不認(rèn)類型筑辨,只要包含即可俺驶,明顯log1更多選擇可以賦值給更小選擇的

函數(shù)綜合

//函數(shù)聲明
function run1():void{

}
//匿名函數(shù)
let run2=function():number{
    return 123;
}

let fun3=function(name:string,age:number):string{
    return name+'---'+age;
}
// console.log(fun3('zq',12));
//可選參數(shù):必須是再最后面,不能再前面
function fun4(name:string,age?:number):void{}
fun4('zq') 

//默認(rèn)參數(shù):可選參數(shù)可以再默認(rèn)參數(shù)之前
function fun5(name?:string,age:number=20):void{}
fun5('zq') 

//剩余參數(shù)
function fun6(...res:number[]):number{
    let sum=0;
    for (let index = 0; index < res.length; index++) {
        sum+=res[index];
    }
    return sum;
}
// console.log(fun6(1,2,3,4,5,6));//21

//剩余參數(shù)形式二
function fun7(a:number,...res:number[]):number{
    let sum=0;
    for (let index = 0; index < res.length; index++) {
        sum+=res[index];
    }
    return sum;
}
// console.log(fun7(1,2,3,4,5,6));//20

//es5中出現(xiàn)同名函數(shù)棍辕,下面會(huì)替換上面的暮现,即使參數(shù)不同

//函數(shù)重載:必須要有一個(gè)any的實(shí)現(xiàn)
function func(name:string):string;
function func(age:number):number;
function func(str:any):any{
    if(typeof str==='string'){
        return '我叫: '+str
    }else{
        return '我的年齡是: '+str
    }
}

// console.log(func('a'),func(12));我叫: a 我的年齡是: 12

ts中的this

案例一:
let obj={
   a:10,
   fn(){
       //函數(shù)中默認(rèn)this指向是any,通過(guò)下面再配置文件中解決楚昭,而且如果是類似于
       //document中事件的this栖袋,ts會(huì)自動(dòng)推導(dǎo)出類型,this指向不需要下面配置也是事件對(duì)象
      //  "noImplicitThis": true
      console.log(this.a)
        //注意:此時(shí)this的指向只是是否有提示的問(wèn)題抚太,真的執(zhí)行代碼配置文件設(shè)置不設(shè)置值都是10
   }
}
案例二:
let obj={
   a:20,
   fn(this:Document){
      console.log(this.querySelector)
   }
}
document.onclick=obj.fn
說(shuō)明:如果配置配置了this指向"noImplicitThis": true,
則fn中的this指向就是obj對(duì)象塘幅,但是此時(shí)obj.fn指向了
點(diǎn)擊事件,為了有提示信息尿贫,需要手動(dòng)指定this指向this:Document
這個(gè)this參數(shù)其實(shí)是一個(gè)假參數(shù)电媳,ts編譯時(shí)候會(huì)被去掉,純粹是
為了代碼提示而存在庆亡,this指向配置不配置匾乓,修改不修改都不影響最后的結(jié)果

修飾符

public protected(該類和子類能訪問(wèn)) private(類,對(duì)象內(nèi)部) readonly(類又谋,對(duì)象內(nèi)部可用拼缝,其他只讀)

案例一:
class Person{
   readonly n:number;
   constructor(num:number){
      this.n=num;
   }
}
let p=new Person(20)
案例二:簡(jiǎn)寫方式
class Person{
   constructor(public num:number){
      this.n=num;
   }
}
let p=new Person(20)
說(shuō)明:因?yàn)閠s不同于js娱局,構(gòu)造函數(shù)中屬性需要先聲明才能
使用,此時(shí)public num:number此種方式就是相當(dāng)于提前再
class中先聲明了一份

存取器

class Person{
   //私有屬性咧七,大家默認(rèn)的規(guī)則是下劃線
   private _num:number;
   //存取器
   //存取器再ts中不是當(dāng)做方法使用的衰齐,而是被當(dāng)做屬性
   get num():number{
      return this._num
   }
   set num(num:number){
      if(num>0){
         this._num=num;
      }
   }
}
let p=new Person()
p.num=-10
console.log(p.num);//undefined

靜態(tài)

class Person {
   private static instance;
   private constructor() { }
   public static getInstance() {
      if (!Person.instance) {
         Person.instance = new Person();
      }
      return Person.instance;
   }
}
let p=Person.getInstance();//相等
let p1=Person.getInstance();

//注意:靜態(tài)屬性和靜態(tài)方法都可被子類繼承

抽象類

抽象描述一種抽象的概念,無(wú)法被實(shí)例化猪叙,只能被繼承娇斩;無(wú)法創(chuàng)建抽象類的實(shí)例,抽象方法不能在抽象類中實(shí)現(xiàn)穴翩,只能在抽象類的具體子類中實(shí)現(xiàn),而且必須實(shí)現(xiàn)锦积。

abstract class Person {
   constructor() { }
   abstract study():void;
}
class Student extends Person{
   study(): void {
      console.log("學(xué)習(xí)");
   }
}
let s=new Student();
s.study()

重載和重寫

  • 重寫是指子類重寫繼承父類中的方法
  • 重載是指為同一個(gè)函數(shù)提供多個(gè)類型定義
class Animal {
    speak(word:string){
        console.log('a');
    }
}
class Cat {
    //重寫
    speak(word:string){
        console.log('b');
    }
}

重載其實(shí)就是函數(shù)重載

類綜合

class Person{
    private name:string;
    constructor(n:string){
        this.name=n;
    }
    run():void{
        console.log(this.name);
    }

}
/**
 * 類中屬性修飾符
 * public: 公有 都可以訪問(wèn),默認(rèn)值
 * protected: 保護(hù)類型  在該類和子類能訪問(wèn)
 * private: 在該類能訪問(wèn)
 */
class Student extends Person{
    //實(shí)際上在新版本ts芒帕,構(gòu)造函數(shù)在此時(shí)可省略,方法執(zhí)行依然正常
    // constructor(n:string){
    //     super(n)
    // }
    static sex='男';//靜態(tài)屬性

    //靜態(tài)方法里面只能使用靜態(tài)屬性
    static print(){
        console.log("靜態(tài)方法",this.sex);
    }

    //重寫父類方法
    run():void{
        console.log("重寫方法");
    }
}
let s=new Student('zq');
// s.run() //zq ,不重寫父類方法的情況下
// Student.print()

// s.run() //輸出: 重寫方法       重寫父類的方法

/**
 * 抽象類:
 *      提供其他類繼承的基類丰介,不能實(shí)例化
 * abstract關(guān)鍵字定義抽象類和抽象方法背蟆,抽象類中的抽象方法不包含具體實(shí)現(xiàn)并且必須在派生類中實(shí)現(xiàn)
 * 
 * 抽象類中可以有屬性,構(gòu)造函數(shù)哮幢,和非抽象方法
 */

 abstract class Animal {
     name:string;
     constructor(name:string){
        this.name=name;
     }
     abstract eat():any;
     run(){
         console.log(this.name+"   跑步");
     }
 }

 class Dog extends Animal{
     eat() {
         console.log("狗吃飯");
     }
     
 }

 let d=new Dog('pf');
 d.eat();
 d.run();//pf   跑步

接口

  1. 用來(lái)描述對(duì)象的屬性以及類型
interface Point{
    x:number;
    y:number;
}
let ponit:Point={x:0,y:0};
  1. 描述行為的抽象
//接口不能有任何屬性和方法實(shí)現(xiàn)带膀,只能有抽象描述
interface Options{
   num:number;
   //可選的
   name?:string;
   say();
}
class optImpl implements Options{
   num: number;
   constructor(num:number){
      this.num=num;
   }
   say() {
      console.log(this.num+"說(shuō)話");
   }
}
function fn(opts:Options) {
   opts.say()
}
fn(new optImpl(20))
  1. 類可以實(shí)現(xiàn)多個(gè)接口,但是只能繼承一個(gè)父類

接口補(bǔ)充

  • 接口的readonly
interface Circle{
    readonly PI:number;
}
let circle:Circle={
    PI:3.14
}
// circle.PI=0; 無(wú)法分配到 "PI" 橙垢,因?yàn)樗侵蛔x屬性
  • 索引簽名(任意屬性)
/**
 * 索引簽名:
 *    希望規(guī)則是:一組由數(shù)字進(jìn)行key命名的對(duì)象
 * 補(bǔ)充:索引簽名的key類型只能是string或者number
 * 索引簽名在下面?zhèn)鲄r(shí)候垛叨,是可有可沒有的,而且不限制個(gè)數(shù)
 */
interface Options{
   //key是number柜某,value是any類型的數(shù)據(jù)
   [atrr:number]:any;
}

function fn(opts:Options) {
}
fn({
   0:1,
   2:20
})
namespace a{
    interface PlainObject{
        [propNmae:string]:number;//key  value形式嗽元;這樣可以任意多個(gè)值
    }
    let obj:PlainObject={
        x:1,
        y:2,
        z:3
    }
    
    
//這數(shù)組進(jìn)行約束,因?yàn)閿?shù)組的key其實(shí)就是索引喂击,所以本質(zhì)還是key-value形式
    interface UserInterface{
        [index:number]:string;
    }
    let arr:UserInterface=['1','2','3']
}
  • 接口約束構(gòu)造函數(shù)

使用new來(lái)約束構(gòu)造函數(shù)

interface WithNameClass{
    new(name:string):Animal;
}
class Animal{
    //public name:string 就相當(dāng)于 this.name=name了
    constructor(public name:string){}
}

//使用
function createAnimal(clazz:WithNameClass,name:string) {
    return new clazz(name);
}
createAnimal(Animal,'zq');

斷言

interface Options{
   num:number;
   name:string;
}

function fn(opts:Options) {
}
//斷言
//按理說(shuō)必須傳入{num:20,name:"呵呵"}類似的才能通過(guò)
//但是通過(guò)斷言可強(qiáng)制判定傳入?yún)?shù)是什么類型
fn({} as Options)

補(bǔ)充:
let obj={
   num:10,
   name:"saa",
   a:1
}
fn(obj)
說(shuō)明:如果把傳入的參數(shù)先賦值好在傳入剂癌,可以避免規(guī)則檢測(cè)
不會(huì)報(bào)錯(cuò),但是此種情況只能在傳入的obj覆蓋全部所需參數(shù)
情況下翰绊,也就是說(shuō)只能多不能少

接口的兼容性

ts跟類型沒有關(guān)系佩谷,只和有沒有有關(guān)系;簡(jiǎn)單說(shuō):我包含你的监嗜,我就可以給你這種類型傳參

interface Animal{
    name:string;
}
interface Person{
    name:string;
    speak:(words:string)=>void;
}

function getNmae(animal:Animal) {
    console.log(animal.name);
}
let p:Person={
    name:'zq',
    speak(){

    }
}
getNmae(p);
//此處傳p也正確谐檀,因?yàn)锳nimal有的Person都有,所以也符合規(guī)則

函數(shù)類型接口

/**
 * 函數(shù)類型接口
 * 是一個(gè)包含由fn并且值的類型為函數(shù)的結(jié)構(gòu)體
 * 并不是描述函數(shù)結(jié)構(gòu)而是一個(gè)包含函數(shù)的對(duì)象結(jié)構(gòu)
 */
interface Options{
   fn:Function
}
let o:Options={
   fn:function(){

   }
}

/**
 * 下面約定就是函數(shù)結(jié)構(gòu)秤茅,而不是包含有函數(shù)的對(duì)象結(jié)構(gòu)了
 */
interface IFn{
   (x:number):number
}
let fn:IFn=function(x:number){return x}


/**
 * 下面是函數(shù)結(jié)構(gòu)的實(shí)踐
 *    因?yàn)閕nterface的約定稚补,保證了傳參的正確性
 *    在編譯階段避免了出錯(cuò)
 */
interface MouseEventCallBack{
   (e:MouseEvent):any;
}
let fn1:MouseEventCallBack=function(e:MouseEvent){}
document.onclick=fn1;

補(bǔ)充案例

interface AjaxData{
   code:number;
   data:any;
}
interface AjaxCallBack{
   (rs:AjaxData):any
}
function ajax(callback:AjaxCallBack){
   callback({
      code:200,
      data:{}
   })
}

泛型

泛型是指在定義函數(shù)、接口或類的時(shí)候框喳,不預(yù)先指定具體的類型课幕,而是在使用的時(shí)候再指定類型的一種特性厦坛;泛型T作用域只限于函數(shù)內(nèi)部使用

/**
 * 泛型:
 *    很多時(shí)候,類型寫死乍惊,不利于復(fù)用
 */
//泛型變量
function fn<T>(args:T):T{
   return args;
}
function fn1<T,S>(args:T,args1:S):[T,S]{
   return [args,args1];
}

//數(shù)組形式
function fn2<T>(args:T[]):T[]{
   return args;
}
function fn3<T>(args:Array<T>){}

泛型類

class MyArray<T>{
   private _data:T[]=[];
   public push(v:T):number{
      return this._data.length;
   }
}
let a=new MyArray<string>();
a.push("a")

let b=new MyArray<number>();
b.push(1)

泛型類型

//泛型類型
let fn:<T>(x:T,y:T)=>number=function(x,y){
   return Number(x)+Number(y)
}
let fn1=function<T,S>(x:T,y:S):number{
   return Number(x)+Number(y)
}
console.log(fn(1,2));//3
console.log(fn1<number,string>(1,"2"));//3

泛型接口

interface IFN<T,S>{
   (x:T,y:S):S
}
let fn2:IFN<string,number>=function(x,y){
   return Number(x)+Number(y);
}

接口泛型

很奇怪的用法杜秸,不太常用

interface Calculate{
    <T>(a:T,b:T):T
}
let add:Calculate=function<T>(a:T,b:T):T{
<!--報(bào)錯(cuò),因?yàn)閭魅腩愋筒灰欢梢韵嗉?->
    <!--return a+b; -->
    return a;
}
add<number>(1,2);
  • (泛型可以有多個(gè))面試題:不增加中間變量的情況下润绎,交換兩個(gè)變量的值
function swap<A,B>(tuple:[A,B]):[B,A] {
    return [tuple[1],tuple[0]];
}
swap<string,number>(['zq',10]);

默認(rèn)泛型類型

function swap<A=number,B=string>(tuple:[A,B]):[B,A] {
    return [tuple[1],tuple[0]];
}
swap([1,'zq']);
// swap<string,number>(['zq',1]);

類類型

/**
 * 類類型:
 *    表示這個(gè)類型對(duì)應(yīng)的對(duì)象
 */

 //錯(cuò)誤實(shí)例:此時(shí)Array代表就是類類型撬碟,但是需要的參數(shù)是該類
 //對(duì)應(yīng)的構(gòu)造函數(shù)
function getArray1(constructor:Array<number>){
   return new constructor();
}
getArray2(Array)

//補(bǔ)充:p后面的Person就是類類型
let p:Person=new Person();
//下面是構(gòu)造函數(shù)
let fn1:{new ():Person}


//正確寫法
function getArray2(constructor:{new():Array<string>}){
   return new constructor();
}
getArray2(Array)

泛型約束

形式一:
function fn<T extends number>(a:T){
   console.log(a);
}

形式二:
interface Len{
   length:number
}
function fn1<T extends Len>(a:T){
   console.log(a.length);
}
fn1("a")//此時(shí)在fn1(1)則會(huì)報(bào)錯(cuò),因?yàn)閿?shù)字類型沒有l(wèi)ength屬性

接口綜合

//ts自定義方法傳入?yún)?shù)  對(duì)json進(jìn)行約束
function printLabel(labelInfo:{label:string}):void{
    console.log("printlabel");
}

// printLabel('name')//錯(cuò)誤
// printLabel({name:'haha'})//錯(cuò)誤
printLabel({label:'haha'}) //正確

//一莉撇、函數(shù)類型接口
/**
 * 以上只是針對(duì)單一方法進(jìn)行約束呢蛤,那么批量約束呢
 * 1. 屬性接口   對(duì)json的約束
 */
interface FullName{
    firstName:string;
    secondName:string; 
}

function printName(name:FullName){
    console.log(name.firstName,name.secondName);
}
let obj={
    age:20,
    firstName:'zq',
    secondName:'pf',
}
//注意: 傳入對(duì)象引用,只要包含必須項(xiàng)即可棍郎,但是如果直接傳入對(duì)象其障,則不能包含多余屬性
//但是建議,不要添加多余屬性
printName(obj)


/**
 * 2. 可選屬性
 */
interface FullName1{
    firstName:string;
    secondName?:string; //可選屬性
}

function printName1(name:FullName1){
    console.log(name.firstName,name.secondName);
}
printName1({firstName:'zq'})//zq undefined

/**
 * 3.函數(shù)類型接口
 * 對(duì)方法的傳入?yún)?shù)和返回值進(jìn)行約束
 */

 interface encrypt{
     (key:string,value:string):string;
 }
 let md5:encrypt=function(key:string,value:string):string{
    return 'haha';
 }
//1. 可索引接口:數(shù)組涂佃,對(duì)象的約束(不常用)
interface UserArr{
   [index:number]:string;
}
let arr:UserArr=['aaa','bbb']


interface UserObj{
   [index:string]:string;
}
let obj1:UserObj={name:'20'}

//2. 類類型接口: 對(duì)類的約束和抽象類有點(diǎn)相似
interface Animal1{
   name:string;
   eat1(str:string):void;
}
class Dog1 implements Animal1{
   name: string;    
   constructor(name:string){
       this.name=name;
   }
   eat1(str: string): void {
       console.log(this.name,str);
   }
}
let d1=new Dog1('zq');
d1.eat1('haha'); //zq haha
//1. 接口擴(kuò)展:接口繼承其他接口
interface A1{
    eat():void;
}
interface A2{
    fly():void;
}
//接口可以多繼承
interface P1 extends A1,A2{
    run():void
}
//類只能單繼承励翼,但是可以多實(shí)現(xiàn),而且繼承和實(shí)現(xiàn)可并存
class P2 implements P1{
    run(): void {

    }    
    eat(): void {

    }
    fly(): void {

    }
}

泛型綜合

// 泛型基本使用
function getData<T>(name:T):T{
    return name;
}
console.log(getData('zq'));
console.log(getData(12));

//泛型類
class MinClass<T>{
    public list:T[]=[]
    add(value:T):void{
        this.list.push(value)
    }
    min():T{
        let min=this.list[0];
        return min;
    }
}
let m=new MinClass<number>();

// 泛型接口
//1. 方式一
interface ConfinFn{
    <T>(v1:T):T;
}
let fn:ConfinFn=function<T>(v1:T):T{
    return v1;
}
fn<string>('haha')

//2. 方式二
interface ConfinFn1<T>{
    (v1:T):T;
}
function fn2<T>(v1:T):T{
    return v1;
}
let fn3:ConfinFn1<string>= fn2;
fn3('sad')

/**
 *泛類 把類當(dāng)作參數(shù)的泛型類
 */

class User{
    //之所以加underfined是因?yàn)椴怀跏蓟瘓?bào)錯(cuò)辜荠,再多加一個(gè)類型就不報(bào)錯(cuò)了
    username:string|undefined; 
    password:string|undefined;
}

//這樣就可以把各種外部類傳遞進(jìn)來(lái)
class MysqlDB<T>{
    add(user:T):boolean{
        return true;
    }
}
let m1=new MysqlDB<User>();
// m1.add(new User())

命名空間和模塊

export.ts

export namespace B {
    export let url = 'safas';
    export function getData(): any[] {
        return [
            1, 2, 3
        ]
    }
    // export {url,getData} 一次統(tǒng)一暴露汽抚,但是使用此方式,上面的export就不能存在了

    // export default getData 一個(gè)模塊只能用一次,引入方式也有區(qū)別
}

export namespace C{
    export let url1 = 'safas';
    export function getData1(): any[] {
        return [
            1, 2, 3
        ]
    }
}
modules.ts

/**
 * 命令空間: 內(nèi)部模塊伯病,主要用于組指代碼造烁,避免命名沖突(其實(shí)針對(duì)的就是一個(gè)文件同名方法的沖突解決方案)
 * 模  塊 : ts的外部模塊的簡(jiǎn)稱,側(cè)重代碼復(fù)用狱从,一個(gè)模塊里可能有多個(gè)命令空間
 */
import { B,C } from './export';
// import getData from './export';   export default方式導(dǎo)出的時(shí)候的引入方式

//如果導(dǎo)出時(shí)候沒有命名空間 則可以通過(guò)as取別名
import { getData as get } from './export';
B.getData();

裝飾器

  • 方式一:配置文件(開啟裝飾器):"experimentalDecorators": true
  • 方式二:根據(jù)vscode錯(cuò)誤提示(裝飾器錯(cuò)誤提示)也可以自動(dòng)修改
/**
 * 裝飾器:
 *  類裝飾器   屬性裝飾器  方法裝飾器   參數(shù)裝飾器
 * 
 * 裝飾器寫法:
 *      普通裝飾器(無(wú)法傳參)
 *      裝飾器工廠(可傳參)
 * 
 * 通俗的講:裝飾器就是一個(gè)方法
 */

 //1. 類裝飾器
namespace A{
    function logclass(params:any){
        //params其實(shí)就是被裝飾的類
    //    console.log(params);
       //擴(kuò)展屬性
       params.prototype.apiURL='www.zq.com';
       params.prototype.run=function(){
           console.log('run');
       }
    }
   
    @logclass
    class HttpClient{
       getData(){
       }
    }
    let h:any=new HttpClient();
    // console.log(h.apiURL); //www.zq.com
//    h.run()
}



//2. 類裝飾器(帶參數(shù))
namespace B{
    function logclass(params:string){
        //此時(shí)params就是hello
        //target就是被裝飾的類
        return function(target:any){
            // console.log(params,target);
        }
    }
    
    //裝飾的過(guò)程是直接執(zhí)行的膨蛮,不需要實(shí)例化,不需要調(diào)用
    @logclass('hello')
    class HttpClient{
       getData(){
       }
    }
    let h=new HttpClient();
}



/**
 * 重載構(gòu)造的小例子
 * 類的裝飾器表達(dá)式會(huì)在運(yùn)行時(shí)當(dāng)作函數(shù)被調(diào)用季研,類的構(gòu)造函數(shù)作為其唯一的參數(shù)
 * 如果類的裝飾器返回一個(gè)值敞葛,它會(huì)使用提供的構(gòu)造函數(shù)來(lái)替換類的聲明
 */
namespace C{
    function logclass(target:any){
        return class extends target{
            apiUrl='修改路徑';
            getData(){
                console.log('修改前');
                this.apiUrl='修改路徑'+'-----';
                console.log(this.apiUrl);
            }
        }
    }
    
    @logclass
    class HttpClient{
        apiUrl:string|undefined;
        constructor(){
            this.apiUrl='路徑初始化'
        }
       getData(){
           console.log(this.apiUrl);
       }
    }
    let h=new HttpClient();
    // h.getData() //修改前  修改路徑-----
}

/**
 * 屬性裝飾器:
 *  屬性裝飾器表達(dá)式會(huì)在運(yùn)行時(shí)當(dāng)作函數(shù)被調(diào)用,傳入下列2個(gè)參數(shù):
 *      1. 對(duì)于靜態(tài)成員來(lái)說(shuō)是類的構(gòu)造函數(shù)(例如 :Person)与涡,對(duì)于實(shí)例成員是類的原型對(duì)象(例如:Person.prototype)
 *      2. 成員的名字
 */

namespace D{
    function logurl(params:string){
        return function(target:any,propertyName:string){
            // console.log(target,propertyName);
            //雖然這樣可修改惹谐,但是通過(guò)打印發(fā)現(xiàn)target[propertyName]是undefined,很奇怪
            //而且必須這個(gè)屬性如果在構(gòu)造函數(shù)有賦值,構(gòu)造函數(shù)內(nèi)部賦值會(huì)替換裝飾器的賦值驼卖,因?yàn)闃?gòu)造是后執(zhí)行的
            target[propertyName]=params;//相當(dāng)于用@logurl('xxx')的參數(shù)給apiUrl重新賦值
            
            //注意:后面還有Object.defineProperty的形式實(shí)現(xiàn)的氨肌,不直接這么 target[propertyName]=params賦值;因?yàn)橛械氖菦]有參數(shù)的酌畜,需要?jiǎng)討B(tài)監(jiān)聽
        }
    }
    
    class HttpClient{
        @logurl('xxx')
        apiUrl:string|undefined;
       getData(){
           console.log(this.apiUrl);
       }
    }
    let h=new HttpClient();
    // h.getData()
}






/**
 * 方法裝飾器:
 *      會(huì)被應(yīng)用到方法的屬性描述符上怎囚,可以用來(lái)監(jiān)視,修改或者替換方法定義
 * 方法裝飾器參數(shù):
 *  1. 對(duì)于靜態(tài)成員來(lái)說(shuō)是類的構(gòu)造函數(shù),對(duì)于實(shí)例成員是類的原型對(duì)象:{getData: ?, constructor: ?}
 *  2. 成員的名字(方法名稱): "getData" 
 *  3. 成員的屬性描述符: {value: ?, writable: true, enumerable: true, configurable: true};
 * 重點(diǎn): 另外屬性描述器的value屬性就是指向被裝飾的方法
 */


 //方式裝飾器一
namespace D{
    function logMethods(params:any){
        return function(target:any,methodsName:string,desc:PropertyDescriptor){
            // console.log(target,methodsName,desc);
    
            //擴(kuò)展屬性和方法
            target.apiUrl=params;
            target.run=function(){
                console.log(this.apiUrl);
            }
        }
    }
    
    class HttpClient{
        @logMethods('www')
        getData(){
            console.log('執(zhí)行');
        }
    }
    let h:any=new HttpClient();
    // h.getData();//執(zhí)行
    // h.run();//www
}

//方法裝飾器二
namespace E{
    function logMethods(params:any){
        return function(target:any,methodsName:any,desc:PropertyDescriptor){
            /**
             * ? () {
                    console.log('執(zhí)行');
                }
             */
            // console.log(desc.value);
    
            //修改裝飾器的方法恳守,把裝飾器方法里面?zhèn)魅氲膮?shù)修改為string類型
            
            //1. 保存當(dāng)前方法
            let om=desc.value;
            desc.value=function(...args:any[]){
                console.log("執(zhí)行原始方法前");
                args=args.map((value)=>{
                    return String(value)
                })
                //如果需要綁定上下文考婴,甚至傳參到原始方法
                om.apply(this,args);
                console.log("執(zhí)行原始方法后");
            }
            //如果不涉及上下文調(diào)用原始的getData方法,則可以把方法調(diào)用放在外面
            // om();
        }
    }
    
    class HttpClient{
        @logMethods('www')
        getData(...args:any[]){
            args.forEach(element => {
                console.log(element);
            });
        }
    }
    let h:any=new HttpClient();
    // h.getData(1,2,3,4);
    /**
     * 輸出結(jié)果:
     * 執(zhí)行原始方法前
        1
        2
        3
        4
     執(zhí)行原始方法后
     */
}

/**
 * 方法參數(shù)裝飾器:用處不大催烘,可能有復(fù)雜用法沥阱,但是基本可以通過(guò)類裝飾器替代,不必研究
 *      參數(shù)裝飾器表達(dá)式會(huì)在運(yùn)行時(shí)當(dāng)作函數(shù)被調(diào)用伊群,可以使用參數(shù)裝飾器為類的原型增加一些元素?cái)?shù)據(jù)考杉,
 *  參數(shù)列表:
 *  1. 對(duì)于靜態(tài)成員來(lái)說(shuō)是類的構(gòu)造函數(shù)(Person),對(duì)于實(shí)例成員是類的原型對(duì)象:{getData: ?, constructor: ?}   例如:Person.prototype
 *  2. 方法的名字: "getData"
 *  3. 參數(shù)在函數(shù)參數(shù)列表中索引 : 0
 */

 //? 代表可選參數(shù):可傳可不傳
function logParams(params?:any){
    return function(target:any,methodsName:string,index:number){
        // console.log(target,methodsName,index);
        target.apiURL=params;//擴(kuò)展屬性
    }
}

class HttpClient{
    getData(@logParams('xxx') uuid:any){
        console.log(uuid);
    }
}
let h:any=new HttpClient();
h.getData();


/*
* 1. 屬性和方法裝飾器舰始,誰(shuí)先寫誰(shuí)先執(zhí)行
* 2. 方法裝飾器又分為方法的和方法參數(shù)的崇棠,先參數(shù)后方法
* 3. 最后是類裝飾器
* 4. 同類型的,先執(zhí)行后寫的蔽午,從內(nèi)到外
*/
  • 屬性裝飾器和方法裝飾器
namespace a1{
    function upperCase(target:any,prototyName:string) {
        let value=target[prototyName];
        const getter=()=>value;
        const setter=(newVal:string)=>{
            value=newVal.toUpperCase();
        }
        delete target[prototyName];//刪掉之前的屬性描述器
        Object.defineProperty(target,prototyName,{
            get:getter,
            set:setter,
            enumerable:true,
            configurable:true
        })
    }

    //方法的
    function methodEnumerable(params:boolean) {
        //propertyDescriptor:老的屬性描述器
        return function(target:any,prototyName:string,propertyDescriptor:PropertyDescriptor) {
            propertyDescriptor.enumerable=params;
        }
    }
    class Person {
        @upperCase
        name:string='zq';

        @methodEnumerable(true)
        public getName(){

        }
    }
    let p=new Person();
    console.log(p.name);//ZQ
    for (const attr in p) {
        console.log(attr);
    }
}

類型保護(hù)

  • 類型保護(hù)就是一些表達(dá)式易茬,他們?cè)倬幾g的時(shí)候就能通過(guò)類型信息確保某個(gè)作用域內(nèi)變量的類型
  • 類型保護(hù)就是能通過(guò)關(guān)鍵字判斷出分支中的類型

以下是案例:

  • typeof
//最主要就是再對(duì)應(yīng)判斷里面有對(duì)應(yīng)函數(shù)的提示
function double(input: string | number | boolean) {
    if (typeof input==='string') {
        input.toLowerCase();
    }else  if (typeof input==='number') {
        input.toFixed(2);
    }else{
        input;
    }
}
  • instanceof

重點(diǎn)是加了判斷,代碼提示也有了及老,而且不會(huì)提示多余的屬性

class Animal {
   public name:string='zq';
}
class Bird extends Animal{
    public swing:number=2;
}
function getName(a:Animal) {
    if (a instanceof Bird) {
        a.swing;
    } else {
        a.name;
    }
}
  • 鏈?zhǔn)脚袛噙\(yùn)算符
//先判斷a是不是null/underfined,如果是則直接返回null或underfined,否則返回a.b的值
a?.b
  • 可辨識(shí)的聯(lián)合類型

利用聯(lián)合類型中的共有字段進(jìn)行類型保護(hù)的一種技巧范抓,相同字段的不同取值就是可辨識(shí)

interface WarningButton{
    class:'warning',
    text1:'1'
}
interface DangerButton{
    class:'danger',
    text2:'11'
}

type Button=WarningButton|DangerButton;
function getButton(btn:Button) {
    //直接寫骄恶,代碼只提示共有屬性class

    //如下才行
    if (btn.class==='warning') {
        btn.text1;
    }else{
        btn.text2;
    }
}
  • in操作符
interface WarningButton{
    text1:'1'
}
interface DangerButton{
    text2:'11'
}

function getButton(btn:WarningButton|DangerButton) {
    if ('text1' in btn) {
        btn.text1;
    } else {
        btn.text2;
    }
}
  • 自定義的類型保護(hù)

自定義類型保護(hù),其實(shí)就是定義了一個(gè)函數(shù)匕垫,函數(shù)的返回值是一個(gè)類型的謂詞僧鲁,形式是params is Type;params必須是當(dāng)前函數(shù)簽名里面的一個(gè)參數(shù)名

interface WarningButton{
    name1:'1',
    text1:'1'
}
interface DangerButton{
    name2:'2',
    text1:'11'
}

function isWarning(x:WarningButton|DangerButton):x is WarningButton {
    //規(guī)則自定義
    return x.text1==='1';
}

function getButton(btn:WarningButton|DangerButton) {
    if (isWarning(btn)) {
        btn.name1;
    } else {
        btn.name2;
    }
}

類型變換

  • 交叉類型
//多個(gè)類型的疊加象泵,并且的關(guān)系
let b:string&number=


interface Bird{
    name:string;
    fly():void;
}
interface Person{
    name:string;
    eat():void;
}
//交叉類型其實(shí)就是兩個(gè)接口類型的屬性的并集
type BirdMan=Bird&Person;
  • typeof

可以獲取一個(gè)變量的類型

/*
type Person={
    name:string;
    age:number
}
*/

let p={
    name:'zq',
    age:10
}
type Person=typeof p;
let p2:Person={
    name:'qq',
    age:20
}
  • 索引訪問(wèn)操作符

通過(guò)[]獲取一個(gè)類型的子類型

interface Person{
    name:string;
    job:{
        name:string
    }
}
let n:Person['job']['name']='fe';
  • keyof

索引類型查詢操作符

interface Person {
    name: string;
    gender: 'male' | 'female';
    //方式一:添加任意屬性
    // [propName:string]:any;
}


//報(bào)錯(cuò):因?yàn)闊o(wú)法確定傳入的key寞秃,可能Person里面沒有這個(gè)key,所以return報(bào)錯(cuò)
// function getValueKey(val: Person, key: string): any {
//     return val[key];
// }

//方式二
// type PKeys='name'|'gender';
type PKeys=keyof Person;  //返回一個(gè)接口key的集合偶惠;這樣避免修改key之后也要修改此處
function getValueKey(val: Person, key: PKeys): any {
    return val[key];
}

let p: Person = {
    name: 'zq',
    gender: 'female'
};
getValueKey(p,'gender');
  • 映射類型

再定義的時(shí)候用in操作符批量定義

interface Person {
    name: string;
    gender: 'male' | 'female';
}

type PartialPerson={
    //? 代表可選 變成賦值的時(shí)候不需要全部都寫了
    [key in keyof Person]?:Person[key]
}
let p: PartialPerson = {
    name: 'zq',
    // gender:'female'   可以不寫春寿,因?yàn)槌闪丝蛇x的
};

內(nèi)置工具類型

TS中內(nèi)置了一些工具類型來(lái)幫助我們更好的使用類型系統(tǒng),雖然下面案例都是使用接口的,但是實(shí)際上class也可以的

  • Partial

將傳入的屬性由非可選變成可選

interface Person {
    name: string;
    gender: 'male' | 'female';
}
let p: Partial<Person> = {
    name: 'zq'
};

實(shí)現(xiàn)原理

type Partial<T>={
    [key in keyof T]?:T[key]
}
  • Required

將傳入的屬性中的可選項(xiàng)變?yōu)楸剡x項(xiàng)

interface Person {
    name: string;
    gender?: 'male' | 'female';
}
let p: Required<Person> = {
    name: 'zq',
    gender:'female'
};

實(shí)現(xiàn)原理

type Required<T>={
    //注意這里是-?
    [key in keyof T]-?:T[key]
}
  • ReadOnley

屬性變成只讀

interface Person {
    name: string;
    gender?: 'male' | 'female';
}
type ReadOnlyPerson=Readonly<Person>
let p: ReadOnlyPerson = {
    name: 'zq',
    gender:'female'
};
// p.gender='zq';無(wú)法分配到 "gender" 忽孽,因?yàn)樗侵蛔x屬性绑改。

實(shí)現(xiàn)原理

type Readonly<T>={
  Readonly  [key in keyof T]:T[key]
}
  • Pick

從傳入的屬性中摘取某一項(xiàng)返回

interface Person {
    name: string;
    gender?: 'male' | 'female';
}
type PickPerson=Pick<Person,'name'>;
let p: PickPerson = {
    name: 'zq'
};

實(shí)現(xiàn)原理

//keyof T=name|gender 是個(gè)聯(lián)合類型
type Pick<T,K extends keyof T>={
    [key in K]:T[key]
}
  • 映射類型修飾符的控制

TS中增加了對(duì)映射類型修飾符的控制,具體而言兄一,一個(gè)readonly或厘线?修飾符里可以用前綴+或-來(lái)表示這個(gè)修飾符應(yīng)該被添加或移除。TS中部分內(nèi)置工具類型利用了這個(gè)特性(Partial...)

條件類型

再定義泛型的時(shí)候能夠添加進(jìn)邏輯分支出革,泛型使用更靈活

案例一

interface A{
    name1:string
}
interface B{
    name2:string
}
interface C{
    name3:string
}
interface D{
    name4:string
}

//判斷T是不繼承A
//ts判斷是否繼承是根據(jù)屬性造壮,所以即使傳進(jìn)入是A,因?yàn)閷傩远加新钍砸部梢?type Condition<T>=T extends A?B:C;
let c:Condition<A>={name2:'zq'};

案例二

interface A{
    name1:string
}
interface B{
    name2:string
}
interface C{
    name3:string
}
interface D{
    name4:string
}

type Condition<T>=T extends A?B:C;
//其實(shí)最終效果就是 B和C的交集
let c:Condition<A|D>={name2:'zq',name3:'zq1'};

TS內(nèi)置了很多條件類型

  • Exclude

從T可分配的類型中排除U

type E=Exclude<string|number,string>;
let e:E=10;
  • Extract

從T可分配的類型中提取U

type E=Extract<string|number,string>;
let e:E='1';
  • NonNullable

從T中排除null和underfined

type E=NonNullable<string|number|null|underfined>;
let e:E='hello';
let e:E=10;
  • ReturnType

獲取函數(shù)類型的返回類型耳璧,并作為新的類型

function getUserInfo() {
    return {name:'zq',age:10}
}
type UserInfo=ReturnType<typeof getUserInfo>
let u:UserInfo={name:'zq',age:20};
  • InstanceType

獲取構(gòu)造函數(shù)的實(shí)例類型

class Person {
    name:string;
    constructor(name:string) {
        this.name=name;
    }
}
type P=InstanceType<typeof Person>
let p:P={name:'zq'};
let p:P=new Person('zq');

類型聲明

  • 聲明文件可以讓我們不需要將js重構(gòu)為TS成箫,只需要加上聲明文件就可以使用系統(tǒng)
  • 類型聲明再編譯的時(shí)候都會(huì)被刪除,不會(huì)影響真正的代碼
  • 可以把類型聲明放在一個(gè)單獨(dú)的類型聲明文件中
  • 文件命令規(guī)范為*.d.ts
  • @types是一個(gè)約定前綴楞抡,所有第三方聲明的類型庫(kù)都會(huì)有這樣的前綴(例如@types/node @types/jquery)
  • TS核心庫(kù)的類型聲明文件
  • 一般*.d.ts文件都在typings文件夾下面

使用案例

//jquery.d.ts
declare function jQuery(selector: string): any;

declare namespace jQuery {
    function ajax(url: string): void;
}
//需要導(dǎo)出伟众,否則外部無(wú)法使用
export default jQuery;

聲明示例

declare let age: number;
declare function getName(): string;
declare class Animal {
    naem: string
}
declare interface Person {
    name: string
}
//declare內(nèi)部不需要加declare
declare namespace jQuery{
    function ajax(url:string):void;
    let name:string;
    namespace fn{
        function extend(object:any):void;
    }
}

注意:vscode下一般都可以找到,但是我們需要是的特定目錄下找到定義文件召廷,所以可以通過(guò)tsconfig.json文件實(shí)現(xiàn)凳厢。

補(bǔ)充

  1. 無(wú)法重新聲明塊范圍變量“name”

在ts中有個(gè)lib.dom.ts;類似于全局文件竞慢,里面聲明的有name屬性先紫,所以這樣直接寫不行,需要把該ts文件轉(zhuǎn)換成模塊

  1. 代碼里面有export import之類的代碼筹煮,那么這個(gè)文件就變成一個(gè)模塊
  2. ts為dom提供了一整套類型聲明
let root: HTMLElement | null = document.getElementById('root');
//!強(qiáng)行斷言 root不是null,這樣就不會(huì)報(bào)錯(cuò)了遮精,否則root可能為null,說(shuō)白了欺騙編譯器
root!.style.color = 'red';
  1. 包裝對(duì)象 (java中的裝箱拆箱)
let name1: string = 'zf';
// name1.toLowerCase();
let name11 = new String(name1);
name11.toLowerCase();

let isOk1: boolean = true;
let isOk2: boolean = Boolean(1);  //拆箱為boolean
// let isOk3:boolean=new Boolean(1);  報(bào)錯(cuò)  對(duì)象賦值給了基本類型

自動(dòng)在基本類型和對(duì)象類型之間切換;基本類型上沒有方法;在內(nèi)部迅速的完成一個(gè)裝箱的操作败潦,把基本類型迅速包裝成對(duì)象類型本冲,然后用對(duì)象來(lái)調(diào)用方法

  1. 類型斷言
let name2: string | number;

此時(shí)直接調(diào)用name2只能調(diào)用string和number的共同方法;要么調(diào)用前賦值,然后回自動(dòng)推導(dǎo)劫扒;要么就使用類型斷言檬洞,就可以正常調(diào)用方法了;(name2 as string).toLowerCase();

  1. 字面量類型

后面賦值只能是'boy'或'girl'
; let G1:'boy'|'girl';

  1. 使用注意
關(guān)鍵字 作為類型使用 作為值使用
class yes yes
enum yes yes
interface yes no
type yes no
function no yes
var,let,const no yes

例如:interface接口就不能作為值賦值,一般使用最多的就是定義類型

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末沟饥,一起剝皮案震驚了整個(gè)濱河市添怔,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌贤旷,老刑警劉巖广料,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異幼驶,居然都是意外死亡艾杏,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門县遣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)糜颠,“玉大人,你說(shuō)我怎么就攤上這事萧求∑湫耍” “怎么了?”我有些...
    開封第一講書人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵夸政,是天一觀的道長(zhǎng)元旬。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么匀归? 我笑而不...
    開封第一講書人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任坑资,我火速辦了婚禮,結(jié)果婚禮上穆端,老公的妹妹穿的比我還像新娘袱贮。我一直安慰自己,他們只是感情好体啰,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開白布攒巍。 她就那樣靜靜地躺著,像睡著了一般荒勇。 火紅的嫁衣襯著肌膚如雪柒莉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,950評(píng)論 1 291
  • 那天沽翔,我揣著相機(jī)與錄音兢孝,去河邊找鬼。 笑死仅偎,一個(gè)胖子當(dāng)著我的面吹牛跨蟹,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播橘沥,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼喷市,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了威恼?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤寝并,失蹤者是張志新(化名)和其女友劉穎箫措,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體衬潦,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡斤蔓,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了镀岛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片弦牡。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖漂羊,靈堂內(nèi)的尸體忽然破棺而出驾锰,到底是詐尸還是另有隱情,我是刑警寧澤走越,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布椭豫,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏赏酥。R本人自食惡果不足惜喳整,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望裸扶。 院中可真熱鬧框都,春花似錦、人聲如沸呵晨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)何荚。三九已至囱淋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間餐塘,已是汗流浹背妥衣。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留戒傻,地道東北人税手。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像需纳,于是被迫代替她去往敵國(guó)和親芦倒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容