TypeScript基础(三)扩展类型-接口和类型兼容性

接口

TypeScript的接口:用于约束类、对象、函数的契约(标准)

和类型别名一样,接口,不出现在编译结果中

在TypeScript中,接口(Interface)用于定义对象的结构和类型。它是一种约定,用于描述对象应该具有哪些属性和方法。接口可以提高代码的可读性、可维护性和可重用性。

接口的定义使用关键字interface,后面跟着接口的名称和一对花括号。在花括号中,可以定义接口的属性、方法和其他成员。

以下是一个简单的接口示例:

typescript 复制代码
interface Person {
  name: string;
  age: number;
  sayHello: () => void;
}

在上面的示例中,我们定义了一个名为Person的接口,它具有三个成员:nameagesayHello。其中,name是一个字符串类型的属性,age是一个数字类型的属性,而sayHello是一个没有参数和返回值的方法。

我们可以使用该接口来声明变量,并确保变量符合该接口所描述的结构:

typescript 复制代码
let person: Person = {
  name: "Alice",
  age: 25,
  sayHello: () => {
    console.log("Hello!");
  }
};

在上面的示例中,我们声明了一个名为person的变量,并将其赋值为一个对象字面量。该对象字面量符合 Person 接口所描述的结构。

除了描述对象结构外,接口还可以描述函数类型、可选属性、只读属性等特性。

函数类型

typescript 复制代码
interface MathOperation {
  (x: number, y: number): number;
}

let add: MathOperation = (x, y) => x + y;

在上面的示例中,我们定义了一个名为MathOperation的接口,它描述了一个函数类型。该函数接受两个参数 xy,并返回一个数字类型的结果。我们可以使用该接口来声明变量 add,并将其赋值为一个函数。

可选属性

typescript 复制代码
interface Person {
  name: string;
  age?: number;
}

let person1: Person = {
  name: "Alice"
};

let person2: Person = {
  name: "Bob",
  age: 30
};

在上面的示例中,我们将 age 属性标记为可选属性(使用 ? 符号)。这意味着在创建 Person 类型的变量时,可以选择性地包含或不包含 age 属性。

只读属性

typescript 复制代码
interface Point {
  readonly x: number;
  readonly y: number;
}

let point: Point = { x: 10, y: 20 };
point.x = 5; // 编译错误:无法分配到 "x" ,因为它是只读属性。

在上面的示例中,我们将 xy 属性标记为只读属性(使用 readonly 关键字)。这意味着一旦创建了该对象,就无法修改这些属性的值。

总结一下,TypeScript中的接口用于定义对象的结构和类型。它可以描述对象的属性、方法、函数类型、可选属性和只读属性等特性。接口可以提高代码的可读性、可维护性和可重用性。

接口继承

接口继承是指一个接口可以继承另一个接口的成员,从而拥有父接口的属性和方法。通过接口继承,可以实现代码的复用和组合。

示例:

typescript 复制代码
interface Shape {
  color: string;
}

interface Square extends Shape {
  sideLength: number;
}

const square: Square = {
  color: "red",
  sideLength: 10,
};

在上面的示例中,Square 接口继承了 Shape 接口,因此 Square 接口拥有了 color 属性。我们可以创建一个 Square 类型的对象,并且该对象必须包含 colorsideLength 属性。

交叉类型

在 TypeScript 中交叉类型是将多个类型合并为一个类型 。通过 & 运算符可以将现有的多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性。

示例:

typescript 复制代码
type Person = {
  name: string;
};

type Employee = {
  id: number;
};

type Manager = {
  department: string;
};

type EmployeeManager = Employee & Manager;

const employeeManager: EmployeeManager = {
  name: "John",
  id: 123,
  department: "HR",
};

在上面的示例中,我们创建了三个类型别名:PersonEmployeeManager。然后我们使用 & 符号将 EmployeeManager 类型合并为一个新的类型 EmployeeManager。我们创建了一个 employeeManager 对象,它拥有 nameiddepartment 属性。

对于上述示例,A和B包含相同成员T1,但是类型不同。这时候混入后的C成员T1的类型是never。因为number和string类型不可能同时存在。

类型兼容性

TypeScript的类型兼容性是指在类型检查过程中,允许某些类型之间的赋值操作或函数参数传递,即使它们的具体类型不完全匹配。这种灵活性使得TypeScript可以更好地处理不同类型之间的交互和兼容。

TypeScript的类型兼容性规则如下:

1. 结构化类型:如果两个类型具有相同的属性和方法,并且它们的属性和方法具有相同的名称和类型,那么它们是兼容的。这种规则被称为"鸭子类型"或"结构化子类型"。

例如:

typescript 复制代码
interface Animal {
  name: string;
  age: number;
}

interface Person {
  name: string;
  age: number;
  gender: string;
}

let animal: Animal = { name: "Tom", age: 5 };
let person: Person = animal; // 兼容,因为Animal和Person具有相同的属性和方法

2. 函数兼容性:如果一个函数需要传递一个参数,并且该参数需要满足某些条件,那么可以传递满足这些条件的任意函数作为参数。

例如:

typescript 复制代码
type Callback = (result: string) => void;

function process(callback: Callback) {
  callback("success");
}

function handleResult(result: string) {
  console.log(result);
}

process(handleResult); // 兼容,因为handleResult满足Callback函数签名要求

3. 可选属性和参数:如果一个类型具有可选的属性或函数参数,那么它可以兼容没有这些可选项的类型。

例如:

typescript 复制代码
interface Options {
  name: string;
  age?: number;
}

let options1: Options = { name: "Tom" }; // 兼容,因为age是可选的
let options2: Options = { name: "Tom", age: 5 }; // 兼容

function printName(options: Options) {
  console.log(options.name);
}

printName({ name: "Tom" }); // 兼容,因为age是可选的

4. 类型参数:如果一个泛型类型使用了另一个泛型类型作为其类型参数,并且这两个泛型类型之间满足某些条件,那么它们是兼容的。

例如:

typescript 复制代码
interface Container<T> {
  value: T;
}

let numberContainer: Container<number> = { value: 5 };
let anyContainer: Container<any> = numberContainer; // 兼容,因为Container<any>可以接受任意类型的值

总结起来,TypeScript的类型兼容性允许在一定条件下进行赋值和函数参数传递,使得代码更加灵活和易于维护。但需要注意,在某些情况下可能会出现潜在的错误或不一致性,因此在使用时需要谨慎考虑。

类型断言

TypeScript的类型断言是一种告诉编译器某个值的具体类型的方式。它可以在需要明确指定类型的地方使用,以便编译器可以正确地进行类型检查和推断。类型断言有两种形式:尖括号语法和as语法。

1. 尖括号语法

typescript 复制代码
let value: any = "hello";
let length: number = (<string>value).length;
console.log(length); // 输出:5

在上面的例子中,我们将value声明为any类型,然后使用尖括号语法将其断言为string类型。这样就可以访问string类型的属性和方法,如length属性。

2. as语法

typescript 复制代码
let value: any = "hello";
let length: number = (value as string).length;
console.log(length); // 输出:5

与尖括号语法类似,as语法也可以用于进行类型断言。它更加符合JSX的语法规范,并且在React项目中更常见。

需要注意的是,类型断言只是在编译时起作用,并不会影响运行时的行为。它只是告诉编译器某个值应该被视为特定的类型,但如果实际上该值不具备该类型所需的属性和方法,那么在运行时可能会导致错误。

另外,当我们对一个联合类型进行断言时,需要确保被断言的值确实是其中一个类型,否则可能会导致运行时错误。

typescript 复制代码
interface Cat {
  name: string
  run(): void
}
interface Fish {
  name: string
  swim(): void
}
function getPet(): Cat | Fish {
  return {
    name: 'hhh',
    run() {
      console.log('run')
    },
    swim() {
      console.log('swim')
    }
  }
}
let pet = getPet()
(pet as Cat).run() // 断言为Cat类型,可以调用run方法
(pet as Fish).swim() // 断言为Fish类型,可以调用swim方法

在上面的例子中,getPet函数返回一个Cat或Fish类型的值。我们使用类型断言将pet断言为Cat或Fish类型,并根据具体的类型调用相应的方法。

总结起来,类型断言是一种在TypeScript中明确指定值的具体类型的方式。它可以通过尖括号语法或as语法进行表示,并且只在编译时起作用。使用类型断言时需要注意确保被断言的值具备所需的属性和方法,并且在对联合类型进行断言时要谨慎处理。


TypeScript基础(一)基本类型与类型运算

TypeScript基础(二)扩展类型-枚举及其位运算


相关推荐
崔庆才丨静觅4 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60615 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了5 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅5 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅5 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅6 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment6 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅6 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊6 小时前
jwt介绍
前端
爱敲代码的小鱼6 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax