类型别名-交叉类型-函数类型-this类型

75 阅读6分钟

一.类型别名的使用

type NumType = number;
let num: NumType = 23;
//这里使用了联合类型,同时HeType是类型别名
type HeType = number | string | object;
let heVal=23;
​
// num3?可选
type numsType = { num1: number, num2: number, num3?: number }
function sum(nums: numsType) {
  console.log(nums.num1, nums.num2, nums.num3)
}
sum({ num1: 1, num2: 3 })

二.接口的声明

type numsType = { 
  num1: number, 
  num2: number, 
  num3?: number 
}
//类型别名和接口非常相似,在定义对象类型时,大部分时候,你可以任意选择使用。
// 接口interface
//声明的方式
interface newType{
  num1: number, 
  num2: number, 
  num3?: number 
}
function ceshi(nums:newType){
  console.log(nums.num1,nums.num2,nums.num3)
}
ceshi({num1:34,num2:1,num3:8})

两者区别

  1. type类型使用范围更广接口类型;只能用来声明对象;可以使用联合、交叉等复杂类型
  2. 在声明对象时,interface 可以多次声明;可以被合并
interface newType{
  num1: number, 
  num2: number, 
  num3?: number 
}
interface newType{
  num4: number 
}
function ceshi(nums:newType){
  console.log(nums.num1,nums.num2,nums.num3)
}
​
ceshi({num1:34,num2:1,num3:8,num4:4})
  1. interface 继承:
interface Shape {
    color: string;
}
interface Square extends Shape {
    sideLength: number;
}
const square: Square = {
    color: "red",
    sideLength: 10
};
  1. interface被类实现:用于描述类应该具有的成员。当一个类实现了一个接口时,它必须实现该接口中定义的所有成员。
interface Animal {
    name: string;
    makeSound(): void;
}
class Dog implements Animal {
    name: string;
​
    constructor(name: string) {
        this.name = name;
    }
​
    makeSound() {
        console.log("Woof!");
    }
}
const dog = new Dog("Buddy");
dog.makeSound(); // 输出 "Woof!"

三.交叉类型

允许你将多个类型合并为一个类型。通过使用 & 运算符,你可以将多个类型组合在一起,从而创建一个新的类型,该类型包含了所有类型的成员

interface Person {
  name: string;
  age: number;
}
interface Employee {
  id: number;
  department: ()=>void;
}
type EmployeePerson = Person & Employee;
const employeePerson: EmployeePerson = {
  name: "Alice",
  age: 30,
  id: 123,
  department: ()=>{
    console.log("employeePerson")
  }
};

四.字面量类型

字面量类型是 TypeScript 中一种特殊的类型,它表示一个具体的值。字面量类型可以是字符串、数字、布尔值或者符号。

在 TypeScript 中,你可以使用字面量类型来限制变量的取值范围,使其只能取特定的值。这有助于提高代码的可读性和可靠性。

1.字符串字面量类型

let color: "red" | "green" | "blue";
color = "red"; // 合法
color = "yellow"; // 错误,因为 "yellow" 不是允许的值
//常用于封装请求的请求方式限制

2.数字字面量类型

let number: 1 | 2 | 3;
number = 1; // 合法
number = 4; // 错误,因为 4 不是允许的值

3.布尔字面量类型

let truth: true | false;
truth = true; // 合法
truth = false; // 合法
truth = 0; // 错误,因为 0 不是允许的值

通过使用字面量类型,你可以明确地指定一个变量只能取特定的值,从而在编译时捕获潜在的错误。这在一些特定的情况下非常有用,例如定义枚举类型、状态标识等

五.类型断言as

类型断言是一种方式,用于告诉编译器一个值的类型。当你比编译器更清楚某个值的类型时,可以使用类型断言来覆盖 TypeScript 的类型推断。as 关键字是类型断言的一种方式。

有两种形式的类型断言:

1.尖括号语法

let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;

2. as 语法

let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;

两种语法的效果相同,都是将 someValue 断言为 string 类型,以便获取其 length 属性。在实际使用中,as 语法更为常见,因为它不会与 JSX 的语法冲突。

注意:类型断言不会在运行时进行类型检查或转换。它们只是在编译阶段告诉编译器将一个值视为特定的类型。因此,如果类型断言不正确,可能会导致运行时错误。因此,要谨慎使用类型断言,最好是避免在不确定的情况下使用它们。

六.非空类型断言!

非空断言使用的是!,表示可以确定某个标识符是有值的,跳过 ts 在编译阶段对它的检测

let someValue: string | null = "hello";
let strLength: number = someValue!.length; // 使用非空类型断言告诉编译器,someValue 不会为 null

七.类型缩小

通过一些操作或条件判断来缩小变量的类型范围,使得在后续代码中 TypeScript 能够更准确地推断变量的类型。

1. typeof 类型保护

function printAll(strs: string | string[] | null) {
    if (typeof strs === "object") {
        for (const s of strs) { // strs 的类型被缩小为 string[]
            console.log(s);
        }
    } else if (typeof strs === "string") {
        console.log(strs); // strs 的类型被缩小为 string
    }
}
​

2.平等缩小

对变量进行相等性检查,以缩小其类型范围的方法

let x: string | number = "hello";
if (x === "hello") {
    // 在这里,x 被缩小为 string 类型
    console.log(x.toUpperCase());
} else {
    // 在这里,x 被缩小为 number 类型
    console.log(x.toFixed(2));
}

3. instanceof 类型保护

class Animal {}
class Dog extends Animal {
    bark() {}
}
​
function makeSound(animal: Animal) {
    if (animal instanceof Dog) {
        animal.bark(); // animal 的类型被缩小为 Dog
    }
}
​

4. in 操作符类型保护

Javascript 有一个运算符,用于确定对象是否具有带名称的属性:in运算符

如果指定的属性在指定的对象或其原型链中,则in 运算符返回true;

interface Circle {
    radius: number;
}
interface Square {
    sideLength: number;
}
function getArea(shape: Circle | Square): number {
    if ("radius" in shape) {
        return Math.PI * shape.radius ** 2; // shape 的类型被缩小为 Circle
    } else {
        return shape.sideLength ** 2; // shape 的类型被缩小为 Square
    }
}
​

八.函数类型

  • 在JavaScript开发中,函数是重要的组成部分,并且函数可以作为一等公民(可以作为参数,也可以作为返回值进行传递)。
  • 那么在使用函数的过程中,函数是否也可以有自己的类型呢?
  • 可以编写函数类型的表达式(Function Type Expressions),来表示函数类型;
1. 函数表达式

通过将函数赋值给一个变量来定义函数类型。

```
// 格式:(参数列表)=>返回值
type SubtractType = (x: number, y: number) => number
let subtract: SubtractType = function (x: number, y: number): number {
  return x - y;
};
```

subtract 变量的类型也是 (x: number, y: number) => number

2.接口定义函数类型

使用接口来定义函数类型

    interface Calculator {
        (x: number, y: number): number;
    }
    let divide: Calculator = function(x: number, y: number): number {
        return x / y;
    };

Calculator 接口定义了一个函数类型,然后将 divide 变量声明为 Calculator 类型。

3.函数调用签名

描述一带有属性的函数,可以在一个对象里类型中写一个调用签名

// 函数类型表达式
type oldType = (x: number, y: number) => number'

// 函数调用签名(从对象的角度来看待这个函数,也可以有其他属性)
interface NewType{
  name:string,
  age:number
  (num31:number):number
}

const foo:NewType=(num1:number):number=>{
  return 234
}
foo.name="1231"
foo.age=34

foo(234)

开发中如何选择:

  1. 如果只是描述函数类型本身(函数可以被调用),使用函数类型表达式(Function Type Expressions)
  2. 如果在描述函数作为对象可以被调用,同时也有其他属性时,使用函数调用签名(Call·signatures)

4.函数可选参数

  1. 可选参数:类型是number|undefined联合类型
function foo(x: number, y?: number) {
  if (y !== undefined) {
    // 这里使用到了类型缩小
    console.log(y + 10)
  }
}
foo(10);//如果上文没有?:number会进行报错提示
foo(10, 20)
  1. 参数默认值:
    1. 有默认值的情况下,参数的类型注解可以省略;
    2. 有默认值的参数,是可以接收一个 undefined的值
//同样可以认为联合类型
function foo(x: number, y = 100) {
  console.log(y + 10)
}
foo(10);
foo(10, 20)