【面试必备】TypeScript 1小时速成

146 阅读6分钟

类型

类型注解

  • : 类型
    

几种类型注解示例

类型语法形式
数字类型number
布尔类型boolean
字符串类型string
符号类型symbol
Void类型void
Null类型null
Undefined类型undefined
Never类型never
任意类型any
数组类型T[]
元组类型[T0, T1, ...]
枚举类型enum T { ... }
函数类型(p1: T1, p2: T2, ...) => T
类类型T
构造器类型new (p1: T1, p2: T2, ...) => R
对象类型{ ... }interface T { ... }
联合类型`T1
交叉类型T1 & T2 & ...

简单类型

  • let a : string = "this is a"
    let b : number = 1
    let c : boolean = true
    
    interface interF { 
        // 属性间可以用,/;/换行符进行连接
    	name:string,
    	sex?:string
    }
    let d : interF = {
        name:"ly"
    }
    
    function fun (param1 : string , param2 : number): void{
        //TODO
    }
    let fn = fun
    

对象类型

  • // 声明一个值为对象字面量
    let man = {name: 'joye', age: 30};
    
    // 等价于
    let man: {name: string; age: number} = {name: 'joye', age: 30};
    

接口类型

对象字面量
  • 对象字面量在直接赋值的时候,编译器会检查字面量类型是否完全匹配,多一个或少一个属性都会报错。

  • interface Person {
      name: string;
      age: number;
    };
    
    // 定义一个对象字面量male
    let male = {
      name: 'joye',
      age: 30,
      gender: 'male'
    };
    
    // 正确,male包含Person接口的所有属性
    let man: Person = male;
    
    //错误,直接赋值时会严格检查接口属性定义,多或少都不行
    let man : Person = {
      name: 'joye',
      age: 30,
      gender: 'male'
    };
    
函数
  • let fn : (name: string, age: number)=>void 
    //等价于
    let fn: { (name: string, age: number): string; } 
    
可索引值
  • 数组

    • // 描述一个数组
      interface StringArray {
        [index: number]: string;
      }
      
  • 对象

    • // 描述一个对象
      interface MyObject {
        [index: string]: string;
      }
      
  • 类数组对象

    • 由于JavaScript会将数字索引转换为字符串索引,数字索引和字符串索引的值的类型必须相等,或者数字索引的返回值必须是字符串索引返回值类型的子类型

    • // 正确
      interface IndexObj {
          [x: number]: string;
          [x: string]: string;
      }
      // 错误,数字索引的值和字符串索引的值不匹配
      // error TS2413: Numeric index type 'number' is not assignable to string index type 'string'
      interface IndexObj {
          [x: number]: number;
          [x: string]: string;
      }
      
  • // 定义一个类
    class NewClass {}
    
    // 用接口来描述这个类类型
    interface MyClass {
      new(): NewClass;
    }
    
    // 声明一个变量为描述这个类的接口类型并初始化
    let myClass: MyClass = NewClass;
    

数组类型

  • : []

函数类型

  • : (a?:string,b:symbol) => void
    
  • 参数返回值进行显示类型注解

  • 可选参数必选参数之前

复合类型

  • 交叉类型

    • T1 & T2 & ...
      
  • 联合类型

    • T1 | T2 | ...
      
  • 高级联合

    • 值与类型 / 值与值 / 类型与类型 混合

    • let u: 99 | "A" | boolean | string ;
      
  • keyof 关键字

    • 取出全部interface中定义的键名

    • interface student{
      	grade:string
      	year:string
      }
      let stud_attr :keyof student //等价于 let stud_attr : "grade" | "year"
      

枚举类型

  • 具有自增性,默认值为数字值

类类型

  • ES6

    • class people{
      	//实例属性
      	year = 10;
      	coustructor(){
      		//实例属性也可以定义在构造函数中
      		this.mood = "happy"
      	}
      	sleep(){
      		//实例方法
      	}
      	static peopleMethod(){
      		//类的静态方法
      	}
      }
      //类的静态属性
      people.peopleOnlyAttr = "类"
      
  • TS

    • class people{
          // age属性未显式添加修饰符,默认为public
          age: number; 
      	//实例属性 被保护,可以在派生类(继承父类的子类)被访问
      	protected year: number = 10;
      	public sleep():void{
      		//实例方法
      	}
      	//不能在声明它的类外部访问
      	 private name: string;
      	// 定义静态属性并初始化
        	static greeting: string = 'world';
        	constructor(theName: string) { this.name = theName; }
      }
      
    • 抽象类、抽象方法

      • 抽象类主要是用来被继承使用,抽象方法必须在派生类中必须被实现

      • 抽象方法必须在抽象类中存在

      • 抽象类可以没有抽象方法

      • // Animal是抽象类
        abstract cLass Animal{
        	//抽象方法,没有方法体
        	abstract type( private typeOfAnimal:string):void
        }
        // 正确,抽象方法被实现
        class Dog extends Animal {
          makeSound(): void{
            // ...
          }
        }
        

类型推导

  • 编译器自动推导出绝大部分未注解的类型

  • // 变量被自动推导为字符串类型 string
    let a = "this is a"
    // 等价于
    let a : string = 'hello world';
    
    // 返回值被自动推导为数字类型 number
    function isNum(param: number) {
      return param;
    }
    // 等价于
    function isNum(param: number): number {
      return param;
    }
    

类型查询

  • //a 待注解方
    //b 被推导方 
    a :typeof b
    
    • 待注解方使用 typeof 去根据被推导方类型进行推导,从而给自己进行显式类型注解
  • // 函数fn为函数
    function fn(){}
    
    // 通过类型查询声明d的类型为fn的类型
    let d: typeof fn // 等价于 let d: () => void
    

泛型

  • 函数名/类名/接口名 <T1,T2,T3...>
  • 定义没有确定函数、类、接口的类型,在调用时在赋予具体的类型

泛型函数

function fun<T1>(param1:T2):void{
	//TODO
}
let funMethod : string = fun <string> ("hello") 

泛型类

class People<T1>{
	name:T2
	show<T3>():T2{
	}
}

let man:People<string> = new People<string>()
a.name = "ly"

泛型接口

interface inter<T>{
	attr:T
}
let a : inter<string> = "s"
let b : inter<number> = 10

function fun():void{}
let c : inter<typeof fun> = {
	attr(){}
}

泛型约束

interface hasLength {
	length:number.
}
//在未具体指定泛型(T)的实际类型时,如调用该类型的具体对象(如arg)的具体属性(length)
//需要使用 extends 泛型约束关键字 进行接口的约束
function getLength<T extends hasLength>(arg:T):number{
	return arg.length
}
  • 在未具体指定泛型(T)的实际类型时,如调用该类型的具体对象(如arg)的具体属性(length)

  • 指定泛型默认值

    interface MyType<T = string> {
      value: T;
    }
    

泛型数组

Array<T> 
let arr: Array<number> = [1, 2, 3];

类型转换

类型别名

  • 对原始类型的一个引用,完全等价于原类型

  • 对原始类型的一个概括总结,提高类型注解的可读性

    //联合类型别名
    type stringOrNumber = string | number
    type sexs = "boy" | "girl"
    //泛型的实际类型别名
    type types = typeAll<string,number>
    //泛型函数别名
    type fun<T> = (data:T) => void
    

类型断言

  • 在没有明确指定某个变量的类型时,后续要用到该变量的具体属性,需要对变量进行类型断言

  • 为编译器进行类型解释

    class Animal{}
    class Cat extends Animal{
    	sleep:(time:number)=>number{
    		return number
    	}
    }
    let katty = new Cat()
    //编译报错,默认katty为Animal类型
    katty.sleep(8)
    //应为katty进行类型断言
    (katty as Cat).sleep(88)
    //或者
    (<Cat>katty).sleep(88)
    

命名空间

命名空间

  • namespace产生一块新的作用域

  • 命名空间内的变量外部无法访问

  • 如需访问成员或者命名空间本身,都需要在声明时通过export进行导出

    namespace fruit{
    	export let apple = "red"
    	let banana = "yellow"
    	function eat(){
    		banana = "yellow,More"
    	}
    }
    //正确
    let apple : string = "error"
    //编译报错,banana为friut命名空间内的变量,未导出,不能进行访问
    let banana : string = fruit.banana
    

    对命名空间成员的访问,类似对象成员的访问,都是用点号运算符 .

空间拆分

  • 命名空间拆分时要注意拆分后的命名空间成员依然无法互相访问
  • 需要访问的空间或成员要增加export

空间嵌套

  • 命名空间支持多层嵌套

空间别名

  • 对命名空间进行重命名
  • 通常在嵌套过深的命名空间中进行使用
namespace A{
    export namespace B {
        export namespace C {
          export let msg = 'hello world';
        }
    }
}
import cc = A.B.C
import cmsg = A.B.C.msg

理解声明

内部声明

  • 在使用ts的过程中的ts语法

外部声明

  • 引用第三方库时TS无法识别,declare进行类型声明

  • 不能在声名时初始化

    declare let $ : (selector:string) => { html:()=>void }
    

三斜线指令和 .d.ts

  • 三斜线指令
    • 通常将TS声明文件进行引入
    • 在编译阶段,被依赖文件 jquery.d.ts 将被包含进来,就像将被依赖文件的源码展开在依赖声明处一样
  • .d.ts
    • 通常使用 .d.ts文件进行ts类型声明汇总
// jquery.d.ts 文件
declare let $: (selector: string) => {
  html: (content: string) => void;
};

// main.ts 文件
// path 引用工程内文件
// types 引用 node_modules/@types 文件夹下的类型的依赖,不包含路径信息
/// <reference path="./jquery.d.ts" />

// 等价于将代码在三斜线指令处展开
declare let $: (selector: string) => {
  html: (content: string) => void;
};
$('body').html('hello world');