TypeScript 类、泛型的使用实践记录 | 青训营

51 阅读5分钟

TypeScript 是一种强类型的 JavaScript 超集,它允许开发者在编写 JavaScript 代码时添加类型注解,以提供更强大的类型检查和代码提示。在 TypeScript 中,泛型(Generics)是一种强大的工具,可以用于创建可重用的、灵活的、类型安全的代码组件。。它允许我们在定义类、函数和接口时使用可变类型参数,从而可以在使用这些类、函数或接口时指定具体的类型。

使用TypeScript泛型的场景和技巧:

  1. 类泛型:可以在定义类时使用泛型,使类的属性和方法可以处理不同类型的数据。例如,我们可以创建一个容器类来存储任意类型的数据:
class Container<T> {
  private data: T[];
  
  constructor() {
    this.data = [];
  }
  
  add(item: T) {
    this.data.push(item);
  }
  
  get(index: number): T {
    return this.data[index];
  }
}

使用时,我们可以指定容器中存储的数据类型:

const numberContainer = new Container<number>();
numberContainer.add(1);
numberContainer.add(2);
console.log(numberContainer.get(1)); // 输出 2

const stringContainer = new Container<string>();
stringContainer.add("hello");
stringContainer.add("world");
console.log(stringContainer.get(0)); // 输出 "hello"
  1. 函数泛型:可以在定义函数时使用泛型,使函数能够处理多种类型的参数和返回值。例如,我们可以创建一个函数来判断两个值是否相等:
function isEqual<T>(value1: T, value2: T): boolean {
  return value1 === value2;
}

使用时,我们可以指定具体的类型:

console.log(isEqual<number>(1, 1)); // 输出 true
console.log(isEqual<string>("hello", "world")); // 输出 false
  1. 接口泛型:可以在定义接口时使用泛型,使接口的属性和方法可以处理不同类型的数据。例如,我们可以创建一个接口来表示具有通用索引器的对象:
interface Indexable<T> {
  [index: string]: T;
}

使用时,我们可以指定具体的类型:

const data: Indexable<number> = {
  "a": 1,
  "b": 2,
  "c": 3,
};
console.log(data["b"]); // 输出 2
  1. 类型约束:可以使用类型约束来限制泛型的类型。例如,我们可以创建一个函数来计算数组的和,但只接受数字数组:
function sum<T extends number[]>(values: T): number {
  let result = 0;
  for (let value of values) {
    result += value;
  }
  return result;
}

使用时,传入非数字数组会报错:

console.log(sum([1, 2, 3])); // 输出 6
console.log(sum(["a", "b", "c"])); // 报错

总结起来,TypeScript中的泛型是一种强大的编程工具,可以增加代码的灵活性和安全性。可以在类、函数和接口的定义中使用泛型,通过泛型参数来指定具体的类型。同时,可以使用类型约束来限制泛型的类型,以增加代码的健壮性。

TypeScript 类、泛型的使用实践记录:

1. 基本的泛型类示例:

class Container<T> {
  private value: T;

  constructor(initialValue: T) {
    this.value = initialValue;
  }

  getValue(): T {
    return this.value;
  }

  setValue(newValue: T) {
    this.value = newValue;
  }
}

const numberContainer = new Container<number>(42);
console.log(numberContainer.getValue()); // Output: 42

const stringContainer = new Container<string>("Hello");
console.log(stringContainer.getValue()); // Output: Hello

2. 泛型约束:

泛型约束可以限制泛型类型参数的范围,使代码更灵活且类型安全。

interface Lengthwise {
  length: number;
}

function printLength<T extends Lengthwise>(input: T) {
  console.log(`Length: ${input.length}`);
}

printLength("Hello"); // Output: Length: 5
printLength([1, 2, 3]); // Output: Length: 3
// printLength(42); // Error: Argument of type '42' is not assignable to parameter of type 'Lengthwise'.

3. 泛型类与类型约束结合使用:

class ArrayPrinter<T extends Lengthwise> {
  constructor(private items: T[]) {}

  printAllLengths() {
    this.items.forEach(item => {
      console.log(`Length: ${item.length}`);
    });
  }
}

const stringArrayPrinter = new ArrayPrinter(["Hello", "TypeScript"]);
stringArrayPrinter.printAllLengths(); // Output: Length: 5, Length: 10

const numberArrayPrinter = new ArrayPrinter([1, 2, 3, 4]);
numberArrayPrinter.printAllLengths(); // Output: Length: 1, Length: 1, Length: 1, Length: 1

4. 泛型与函数组合使用:

function mapArray<T, U>(array: T[], mapper: (item: T) => U): U[] {
  return array.map(mapper);
}

const numbers = [1, 2, 3, 4];
const squaredNumbers = mapArray(numbers, num => num * num);
console.log(squaredNumbers); // Output: [1, 4, 9, 16]

const strings = ["Hello", "TypeScript"];
const stringLengths = mapArray(strings, str => str.length);
console.log(stringLengths); // Output: [5, 10]

5. 泛型在异步编程中的应用:

async function fetchData<T>(url: string): Promise<T> {
  const response = await fetch(url);
  const data = await response.json();
  return data as T;
}

interface User {
  id: number;
  name: string;
}

const user = await fetchData<User>("https://api.example.com/user/1");
console.log(user.id, user.name);

以上示例展示了 TypeScript 类和泛型的一些常见用法和场景。泛型可以应用于类、函数以及异步操作,它们的灵活性和类型安全性可以显著提高代码的可维护性和可扩展性。通过合理地使用泛型约束,可以进一步增加代码的灵活性和安全性。

TypeScript中泛型的使用方法:泛型允许我们在定义函数、类或接口时使用参数化类型,以增加代码的灵活性和重用性。通过使用<T>来声明泛型类型参数,并将其作用于函数的参数、函数的返回值、类的成员变量等。

泛型的使用场景:

  1. 函数中对参数类型进行约束或处理:可以使用泛型来处理不同类型的参数,例如数组的映射、过滤等操作。
  2. 类中需要接收不同类型的数据:可以使用泛型来定义类的成员变量或方法的参数类型,使其可以适应不同类型的数据。
  3. 对数组、集合等数据结构进行封装:通过使用泛型来封装数组、集合等数据结构,可以提供更强大的类型检查和代码提示。

使用类型约束增加代码的灵活性和安全性:通过使用类型约束,我们可以限制泛型类型的范围,从而增加代码的灵活性和类型安全性。例如,使用接口来约束泛型类型的属性,以确保参数满足特定条件。这样能够在编译阶段捕获潜在的类型错误,并提供更准确的代码提示。

例子:

interface Lengthwise {
  length: number;
}

function printLength<T extends Lengthwise>(input: T) {
  console.log(`Length: ${input.length}`);
}

printLength("Hello"); // Output: Length: 5
printLength([1, 2, 3]); // Output: Length: 3
// printLength(42); // Error: Argument of type '42' is not assignable to parameter of type 'Lengthwise'.

在上述例子中,通过使用extends关键字约束泛型类型必须实现Lengthwise接口,从而确保传入的参数具有length属性。这样我们就可以在编译阶段捕获传入参数不符合要求的错误。