第三节:TypeScript类型补充和函数详解(参数、返回值、类型、参数【可选/默认】、剩余参数、this、重载)

一. TypeScript类型补充

1. 类型断言

 有时候TypeScript无法获取具体的类型信息,这个我们需要使用类型断言(Type Assertions) ,TypeScript只允许类型断言转换为 更具体 或者 不太具体 的类型版本,此规则可防止不可能的强制转换。

 符号:as

// 1.类型断言 as
const el = document.getElementById("why") as HTMLImageElement
el.src = "url地址"

// 2.另外案例: Person是Student的父类
class Person { }
class Student extends Person {
    studying() { }
}
function sayHello(p: Person) {
    (p as Student).studying()
}
const stu = new Student()
sayHello(stu)

2. 非空断言

 我们确定传入的参数是有值的,这个时候我们可以使用非空类型断言。非空断言使用的是 ! ,表示可以确定某个标识符是有值的,跳过ts在编译阶段对它的检测

 符号:!

// message? -> undefined | string
function printMessageLength(message?: string) {
    // if (message) {
    //   console.log(message.length)
    // }
    // vue3源码中很多这种写法
    console.log(message!.length)
  }
  
  printMessageLength("aaaa")
  printMessageLength("hello world")

3. 可选链

 可选链事实上并不是TypeScript独有的特性,它是ES11(ES2020)中增加的特性:

 符号  ?.

   它的作用是当对象的属性不存在时,会短路,直接返回undefined,如果存在,那么才会继续执行,  虽然可选链操作是ECMAScript提出的特性,但是和TypeScript一起使用更版本。

// 定义类型  
type Person = {
    name: string
    friend?: {
        name: string
        age?: number,
        girlFriend?: {
            name: string
        }
    }
}

// 声明对象
const info: Person = {
    name: "why",
    friend: {
        name: "kobe",
        girlFriend: {
            name: "lily"
        }
    }
}


// 另外一个文件中
console.log(info.name)
// console.log(info.friend!.name)
console.log(info.friend?.name)
console.log(info.friend?.age)
console.log(info.friend?.girlFriend?.name)
View Code

4. !!运算符

 将一个其他类型转换成boolean类型;类似于Boolean(变量)的方式;

const message = "Hello World"

// const flag = Boolean(message)
// console.log(flag)

const flag = !!message
console.log(flag)

5. ??运算符

 它是ES11增加的新特性;

 空值合并操作符??)是一个逻辑操作符,当操作符的左侧是 null 或者 undefined 时,返回其右侧操作数,否则返回左侧操作数 。

let msg1: string | null = 'hello ts';
let msg2: string | null = null;

const result1 = msg1 ?? 'hello js';
// 上面等价于
const result2 = msg1 ? msg1 : 'hello js';
console.log(result1);
console.log(result2);

const result3 = msg2 ?? 'hello js';
// 上面等价于
const result4 = msg2 ? msg2 : 'hello js';
console.log(result3);
console.log(result4);

6. 字面量

 字面量类型(说白了就是自己声明了一个类型)
// 1. 如下,这里声明的字面量类型为 'hello ts'
let msg1: 'hello ts' = 'hello ts';
// msg1='hhh';   //报错,类型错误,因为这里的类型是hello ts

//2. 字面量类型的意义, 就是必须结合联合类型
type Alignment = 'left' | 'right' | 'center'

let align: Alignment = 'left'
align = 'right'
align = 'center'

7. 类型缩小

 在给定的执行路径中,我们可以缩小比声明时更小的类型,这个过程称之为 缩小;

 常见的类型保护有如下几种:

  A. typeof

  B. 平等缩小(比如===、!==)

  C. instanceof  (检查一个值是否是另一个值的“实例” )

  D. in

// 1.typeof的类型缩小
type IDType = number | string
function printID(id: IDType) {
    if (typeof id === 'string') {
        console.log(id.toUpperCase())
    } else {
        console.log(id)
    }
}

// 2.平等的类型缩小(=== == !== !=/switch)
type Direction = "left" | "right" | "top" | "bottom"
function printDirection(direction: Direction) {
    // 1.if判断
    // if (direction === 'left') {
    //   console.log(direction)
    // } else if ()

    // 2.switch判断
    // switch (direction) {
    //   case 'left':
    //     console.log(direction)
    //     break;
    //   case ...
    // }
}

// 3.instanceof  检查一个值是否是另一个值的“实例”
function printTime(time: string | Date) {
    if (time instanceof Date) {
        console.log(time.toUTCString())
    } else {
        console.log(time)
    }
}

class Student {
    studying() { }
}
class Teacher {
    teaching() { }
}
function work(p: Student | Teacher) {
    if (p instanceof Student) {
        p.studying()
    } else {
        p.teaching()
    }
}
const stu = new Student()
work(stu)

// 4. in(用于确定对象是否具有带名称的属性:in运算符,如果指定的属性在指定的对象或其原型链中,则in 运算符返回true;)
type Fish = {
    swimming: () => void
}
type Dog = {
    running: () => void
}
function walk(animal: Fish | Dog) {
    if ('swimming' in animal) {
        animal.swimming()
    } else {
        animal.running()
    }
}

const fish: Fish = {
    swimming() {
        console.log("swimming")
    }
}
walk(fish)
View Code

 

二. TypeScript函数详解

1. 函数自身 参数类型 和 返回值类型

// 1. 函数的参数类型
function sum1(num1: number, num2: number) {
    return num1 + num2;
}

// 2. 函数的返回值类型
// 添加返回值的类型注解,这个注解出现在函数列表的后面:
function sum2(num1: number, num2: number): number {
    return num1 + num2;
}
// 和变量的类型注解一样,我们常情况下不需要返回类型注解,因为TypeScript会根据 return 返回值推断函数的返回类型:
function sum3(num1: number, num2: number) {
    return num1 + num2;
}

2. 作为参数的函数类型

 可以编写函数类型的表达式(Function Type Expressions),来表示函数类型;

 格式为:  (n:xx,m:xx)=>xxx括号里的是参数名和参数类型=>后面的是返回值类型比如: (num1: number, num2: number) => void,代表的就是一个函数类型:

 A. 接收两个参数的函数:num1和num2,并且都是number类型;

 B. 并且这个函数是没有返回值的,所以是void;

// 案例1-函数作为参数进行传递
function calc(m1: number, m2: number, fn: (num1: number, num2: number) => number) {
    return fn(m1, m2);
}
const result1 = calc(10, 20, function (m, n) {
    return m - n;
})
console.log(result1);
const result2 = calc(10, 20, function (m, n) {
    return m * n;
});
console.log(result2);

// 案例2--定义常量时, 编写函数的类型
type myAddFnType = (num1: number, num2: number) => number;
const Add1: myAddFnType = (m, n) => {
    return m + n;
}
console.log(Add1(10, 20));

3. 参数可选类型 

 符号:?

 可选类型需要在必传参数的后面

function foo(x: number, y?: number) {
    if (y) {
        console.log(x+y);
    } else {
        console.log(x);
    }
}

foo(20, 30)
foo(20)

4. 参数默认值

 从ES6开始,JavaScript是支持默认参数的,TypeScript也是支持默认参数的:

 格式: 直接 = 号 ,写上默认值就行了

//通常我们写的顺序: 必传参数 - 有默认值的参数 - 可选参数
function foo(y: number, x: number = 20, z?:number) {
    console.log(x, y)
}

foo(30)

5. 剩余参数

 从ES6开始,JavaScript也支持剩余参数,剩余参数语法允许我们将一个不定数量的参数放到一个数组中。 ts也支持
/* 
    @totalNum: 默认初始值
    @nums:数组
*/
function sum(totalNum: number, ...nums: number[]) {
    let total = totalNum;
    for (const num of nums) {
        total += num;
    }
    return total;
}

console.log(sum(10,100))
console.log(sum(10,100,200))
console.log(sum(10,100,200,300))

6. this的默认推导

// this是可以被推导出来 info对象(TypeScript推导出来)
const info = {
    name: "ypf",
    eating() {
        console.log(this.name + " is eating")
    }
}

info.eating()

7. this的不明确类型

type ThisType = { name: string };

function eating(this: ThisType, message: string) {
  console.log(this.name + " eating", message);
}

const info = {
  name: "why",
  eating: eating,
};

// 隐式绑定
info.eating("哈哈哈");

// 显示绑定
eating.call({name: "kobe"}, "呵呵呵")
eating.apply({name: "james"}, ["嘿嘿嘿"])

8. 函数重载

 函数的重载: 函数的名称相同, 但是参数不同的几个函数, 就是函数的重载
function add(num1: number, num2: number): number; // 没函数体
function add(num1: string, num2: string): string;
function add(num1: any, num2: any): any {
    if (typeof num1 === 'string' && typeof num2 === 'string') {
        return num1.length + num2.length
    }
    return num1 + num2
}
const result1 = add(20, 30)
const result2 = add("abc", "cba")
console.log(result1)
console.log(result2)

// 在函数的重载中, 实现函数是不能直接被调用的
// add({name: "why"}, {age: 18})


// 实现方式二: 函数的重载
function getLength(args: string): number;
function getLength(args: any[]): number;
function getLength(args: any): number {
    return args.length
}
console.log(getLength("abc"))
console.log(getLength([123, 321, 123]))

 

 

 

 

 

!

  • 作       者 : Yaopengfei(姚鹏飞)
  • 博客地址 : http://www.cnblogs.com/yaopengfei/
  • 声     明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
  • 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
 
posted @ 2021-11-03 14:54  Yaopengfei  阅读(1504)  评论(1编辑  收藏  举报