Typescript-高级类型

类型推论

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

鼠标悬停之后,会显示其返回值类型推论

类型兼容

interface IA {
  a: number;
}
var a: IA;
var b: { a: number, b: number } = { a: 1, b: 2 };
a = b

//向下兼容-->少的兼容多的
//多的兼容少的需要加断言
//类的兼容,看里面的属性和方法

高级类型

交叉类型 &

`交叉类型是将多个类型合并为一个类型`
//把现有的多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性
interface IA {
  a: number;
}
interface IB {
  b: number;
}

var a: IA & IB = { a: 1, b: 2 };
console.log(a)//{a: 1, b: 2}


interface IA {
  a: number;
  b: number;
}
interface IB {
  c: number;
  b: number;
}
//两者都有b 写一个就行
var o: IA & IB = { a: 1, b: 2, c: 3 }//{a: 1, b: 2, c: 3}


`对交叉类型 详解`
function extend<T, U>(first: T, second: U): T & U {
  //设置o的类型是T & U
  var o: T & U = {} as T & U;
  //key 为对象中的属性 类型是T
  var key: keyof T;
  for (key in first) {
    //把first中的属性赋值给o
    (<T>o)[key] = first[key];
  }
  //key1 为对象中的属性 类型是U
  var key1: keyof U
  for (key1 in second) {
    //判断key1 是否是o中的属性
    if (!Object.hasOwn(<object>o, key1))
      //若不是 就把second中对应key1的属性放到o中
      (<U>o)[key1] = second[key1]
  }
  return o;
}

联合类型 |

//联合类型表示一个值可以是几种类型之一。 我们用竖线( |)分隔每个类型,所以 number | string | boolean表示一个值可以是 number, string,或 boolean

interface IA {
  a: number;
  c: number;
}
interface IB {
  b: number;
  d: number;
}
var a: IA | IB = { a: 1, c: 2 }
a = { d: 1, b: 2 }
a = { a: 1, b: 2, c: 3 }
//至少要有其中一种类型里的全部的属性
a = { a: 1, b: 2 };//错误



interface Bird {
  fly(): void;
  layEggs(): void;
}
interface Fish {
  swim(): void;
  layEggs(): void;
}

//设置了该函数的返回值是Bird或者Fish
function getSmallPet(): Bird | Fish {
  return <Bird | Fish>{}
}
var o = getSmallPet();
//因为Bird和Fish中都有layEggs方法所以不需要加断言
o.layEggs()

//错误
// if (o.fly) {
//   o.fly();
// }
// 下面这种写法需要每个部分都要断言
if ((<Bird>o).fly) {
  (<Bird>o).fly()
}

类型保护

// 判断当前元素是否是某个类型,以让后面的内容都设置该类型
interface Bird {
  fly(): void;
  layEggs(): void;
}
interface Fish {
  swim(): void;
  layEggs(): void;
}
function getSmallPet(): Bird | Fish {
  return <Bird | Fish>{}
}
var o = getSmallPet();

//封装成一个函数进行使用
function isBird(o: Bird | Fish): o is Bird {
  return (<Bird>o).fly !== undefined;
}
function isFish(o: Bird | Fish): o is Fish {
  return (<Fish>o).swim !== undefined;
}
//在判断的时候就不需要使用泛型了
if (isBird(o)) {
  o.fly();
} else {
  o.swim();
}

if (isFish(o)) {
  o.swim();
} else {
  o.fly();
}


//小案例	改变div的颜色
var div: HTMLDivElement = document.querySelector("div") as HTMLDivElement;
div.addEventListener("click", clickHandler);

function isHTMLElement(o: any): o is HTMLElement {
  return o instanceof HTMLElement;
}
function clickHandler(e: MouseEvent): void {
  if (isHTMLElement(e.target)) {
    if (e.target.nodeName != "DIV") return;
    e.target.style.backgroundColor = "blue";
  }
}

类型别名

// 给string | number这个类型起了一个A的别名
type A = string | number;
var o: A = "a";
o = 1;


interface IA {
  a: number;
  b: number;
}
//给接口IA起了一个A的别名
type A=IA;
//接口可以继承接口也可以继承别名
interface IB extends A {
  c: number;
}
var o: IB = {
  a: 1,
  b: 2,
  c: 3
}

//别名不能继承接口
interface IA{
  a:number;
  b:number;
}
type A={c:number} extends IA//错误


`类型别名有类似于接口的特征`
type A={a:number,b:number};
var o:A={a:1,b:2};



interface IA {
  a: number;
  b: number;
}
var a: IA	// 鼠标放在这个类型上,接口看不到具体内容

type A = { a: number, b: number };
var o1: A	// 鼠标放在这个类型上,别名可以看到具体的内容

使用

`作为值的选项`
type MouseEvent1 = "click" | "mousedown" | "mouseup" | "mousemove";
var a: MouseEvent1;
// if (a === "click") {

// }
switch (a) {
//每次使用一个都会少一个
  case "click":
    break;
  case "mousedown":
    break;
  case "mousemove":
    break;
  case "mouseup":
    break;
}

预定义的有条件类型

1.Exclude<T, U> --T中剔除可以赋值给U的类型。
2.Extract<T, U> -- 提取T中可以赋值给U的类型。
3.NonNullable<T> --T中剔除nullundefined4.ReturnType<T> -- 获取函数返回值类型。
5.InstanceType<T> -- 获取构造函数类型的实例类型。

使用

type A = "click" | "mousedown" | "mousemove" | "mouseup" | "mouseover" | "mouseout";
type B = "mouseover" | "mouseout" | "mouseenter" | "mouseleave";
//这个把 A与B中相同的给剔除了 返回A中剩余的值
type C = Exclude<A, B>;
var c1: C = ""
console.log(c1)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

索引

//索引 用来取值
function fn<T, K extends keyof T>(o: T, key: K): void {
  console.log(o[key])
}

//去类型的方法
interface IA {
  a: number;
  b: number;
}
type a = {
  readonly [P in keyof IA]: IA[P]
}

命名空间 namespace

随着更多验证器的加入,我们需要一种手段来组织代码,以便于在记录它们类型的同时还不用担心与其它对象产生命名冲突。 因此,我们把验证器包裹到一个命名空间内,而不是把它们放在全局命名空间下。
namespace Rect {
  export class Box {
    constructor() {

    }
    public play(): void {
      console.log("play");

    }
  }
}

namespace Circle {
  export class Box {
    constructor() {

    }
    public play(): void {
      console.log("play1")
    }
  }
}

var a: Rect.Box = new Rect.Box();
var b: Circle.Box = new Circle.Box();
a.play();
b.play();



`外部枚举 declare`
//在空间前加declare 当空间当前文件外部时使用不需要导入
//A.ts
declare namespace Box {
  export interface IA {
    a: number;
    b: number;
  }
}
//B.ts
var a: Box.IA = { a: 1, b: 2 };
console.log(a);//{ a: 1, b: 2 }

装饰器

装饰器是一种特殊类型的声明,它能够被附加到类声明,方法, 访问符,属性或参数上。
装饰器使用 @expression这种形式,expression求值后必须为一个函数,它会在运行时被调用,被装饰的声明信息做为参数传入

都是直接设置到原型链中

类装饰器

function fn(className: { new(): Box }) {
  className.prototype.run = function () {
    console.log("run");
  }
}

@fn
class Box {
  constructor() {

  }
  public play(): void {
    console.log("play")
  }
}



`装饰器实现类的继承`
function addWalk(className: { new(): Box | Ball }) {
  className.prototype.walk = function () {
    console.log("walk")
  }
}
interface IWalk{
  walk():void;
}


@addWalk
class Box {
  constructor() {

  }
  run() {

  }
}
@addWalk
class Ball {
  constructor() {

  }
  play() {

  }
}

var a: Box = new Box();
var b: Ball = new Ball();
//调用添加的addWalk方法
(<Box & IWalk>a).walk();
(<Ball & IWalk>b).walk()
console.log(a)
console.log(b);

`一个类可以加多个装饰器`


`类装饰器可以设定泛型和调用类自身的方法`
function addRun<T>(className: { new(): T }) {
  className.prototype.run = function () {
    //调用当前类的自身方法
    this.play();
    // console.log(this) 实例化对象
    console.log("run")
  }
}

interface IRun {
  run(): void;
}

@addRun
class Box {
  constructor() {

  }
  public play() {
    console.log("play");
  }
}

@addRun
class Ball {
  constructor() {

  }
  public play() {
    console.log("play2")
  }
}
var a: Box = new Box();
var b: Ball = new Ball();
(<Box & IRun>a).run();
(<Ball & IRun>b).run();
console.log(a)
console.log(b)

属性装饰器

function format(arg: string) {
  return function (thisArg: Box, prototypeName: keyof Box) {
    // thisArg[prototypeName] = "aaa"
    thisArg[prototypeName] = arg;
    thisArg.arg = 30;
  }
}
class Box {
  @format("aaa")
  public name: string = "a";
  [key: string]: string | number;
  constructor() {

  }
}
var b: Box = new Box();
console.log(b)

类的方法的装饰器

//给类的方法中添加新内容
function supers() {
  return function (thisArg: Box, medthodName: keyof Box, valueDesc: PropertyDescriptor) {
    //valueDesc.value 是play方法
    var fn = valueDesc.value;
    // thisArg是原型链原型对象
    // valueDesc 就是当前装饰方法,现在重写play方法
    valueDesc.value = function () {
      console.log("begin Play")
      // console.log(this);//这个this是实例化对象的this
      fn.call(this)
    }
  }
}
class Box {
  public age: number = 30;
  constructor() {

  }
  @supers()
  public play(): void {
    console.log("play" + this.age)
  }
}

var b: Box = new Box();
b.play();
console.log(b)

参数的修饰器

//参数的修饰器
function setArg(n: number) {
  return function (thisArg: Box, medthodName: keyof Box, value: number) {
    // thisArg是原型链本身
    thisArg.age = n;
  }
}

class Box {
  [key: string]: any;
  constructor() {

  }
  play(@setArg(10) num: number): void {
    console.log(num)
    console.log(this.age)
  }
}
var b: Box = new Box();
b.play(2)
console.log(b)

this总结

1、全局中this
console.log(this);//window

2、函数中的this
//ES6严格模式 undefined 非严格模式window
function fn(this:void){
    console.log(this);
}

var obj={
    play(){
        function fn(this:void){
            console.log(this)
        }
        fn()
    }
}
obj.play()

3、对象中this
var b=3;
var o={
    b:2,
    // 对象属性上的this等于对象外的this指向
    a:this.b,
    c(){
        // 这个this指向当前对象
        console.log(this)
    },
    d:function(){
        // 这个this指向当前对象
        console.log(this);
    }
}

4、普通回调函数中的this
//普通回调函数中 严格模式时this指向undefined,非严格模式this指向window
function fn(f:()=>void):void{
    f();
}
function fn1(this:void):void{
    console.log(this)
}
fn(fn1);

setTimeout(function(this:void){
    console.log(this);
})
var arr=[1,2,3,4];
arr.forEach(function(this:void){
    console.log(this)
})

5、arguments回调函数中
//使用arguments执行回调函数,被调用的函数中this指向调用该函数所在上下文环境中arguments
function fn(f:()=>void){
    arguments[0]();
}
function fn1(this:void){
    console.log(this)
}
fn(fn1);

6、事件回调函数
//事件回调函数中this指向当前侦听事件的对象
document.addEventListener("click",clickHandler);
function clickHandler(this:void,e:MouseEvent){
    console.log(this);
}

7、数组的部分遍历方法中有thisArg参数的回调函数
//当数组部分遍历方法的回调函数中使用this,这个this指向遍历方法的第二个参数thisArg
var arr=[1,2,3,4];
arr.forEach(function(this:void){
    console.log(this)
},{a:1})
arr.forEach()
arr.map();
arr.filter();
arr.find();
arr.findIndex();
arr.findLastIndex();
arr.findLast();
arr.every();
arr.some();
arr.flatMap();


8、箭头函数
var o = {
    play() {

        var obj = {
            a: () => {
                console.log(this);//箭头函数外this的指向
            }
        }
        obj.a();
    }
}
o.play();

var o = {
    play() {
        var arr = [1, 2, 3];
        arr.forEach(() => {
            console.log(this);//o
        })
    }
}

9、call。apply,bind
使用call,apply,bind执行时带入的第一个参数是thisArg
//执行函数时,如果非严格模式时
1.thisArg是引用类型的,this直接指向thisArg,
2.如果是非引用类型的,则先转换为引用类型的该类型,this指向转后引用类型
3.如果是undefined或者null,则this指向window
//如果是严格模式时,thisArg带入是什么值,this就指向这个值
function fn(){
    console.log(this)
}
fn.call({a:1});
fn.apply({a:1});
fn.bind({a:1})()

10、原型链中this指向
//如果函数使用new执行时,这个函数就是构造函数,构造函数中的this指向创建的实例化对象
function Box(this:void){
    console.log(this)
}
// 在原型中this指向当前类创建的实例化对象
Box.prototype.play=function(){
    console.log(this)
}
// 在类静态方法中,函数的方法就是类的静态方法,这里的this指向当前函数Box
Box.run=function(){
    console.log(this)
}
var c:Box=new Box();

11ES6 类中的this
class Box{
    public a:number=1;
     // 实例化属性中如果使用this指向当前实例化对象本身
    public c:number=this.a;
    // 静态属性中如果使用this,指向当前类Box
    public static b:number=2;
    public static d:number=this.b;
    constructor(){
        // 构造函数中this指向当前实例化对象
        console.log(this)
    }
    public play(){
        // 实例化方法中this指向当前实例化对象
        console.log(this)
    }
    public static run(){
        // 静态方法中this指向当前类
        console.log(this)
    }
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值