什么是泛型,如何使用它?

泛型(Generics)是什么?

泛型是TypeScript中一种创建可复用、类型安全组件的工具,它允许你在定义函数、接口或类时不预先指定具体类型,而是在使用时再指定类型参数。这解决了代码复用与类型安全之间的矛盾。

为什么需要泛型?

没有泛型时,通常有两种方式处理不同类型:

  1. 使用any类型(失去类型检查)
  2. 为每种类型重复编写几乎相同的代码

泛型通过参数化类型解决了这个问题,使组件可以支持多种类型同时保持类型安全。

基本使用方法

1. 泛型函数
// 定义泛型函数,T是类型参数(可自定义名称)
function identity<T>(arg: T): T {
  return arg;
}

// 使用时指定类型
const num: number = identity<number>(10);
const str: string = identity<string>('hello');

// 类型推断(可省略显式类型)
const bool = identity(true); // 自动推断T为boolean
2. 泛型接口
// 定义泛型接口
interface Container<T> {
  value: T;
  getValue: () => T;
}

// 实现时指定类型
const numberContainer: Container<number> = {
  value: 100,
  getValue: () => 100
};

const stringContainer: Container<string> = {
  value: '泛型',
  getValue: () => '泛型'
};
3. 泛型类
class Stack<T> {
  private items: T[] = [];

  push(item: T): void {
    this.items.push(item);
  }

  pop(): T | undefined {
    return this.items.pop();
  }
}

// 使用时指定类型
const numberStack = new Stack<number>();
numberStack.push(1);
numberStack.push('2'); // 错误:不能将string分配给number

const stringStack = new Stack<string>();
stringStack.push('hello');

高级特性

1. 泛型约束

限制泛型只能是特定类型或具有特定属性:

// 约束T必须有length属性
interface Lengthwise {
  length: number;
}

function logLength<T extends Lengthwise>(arg: T): T {
  console.log(arg.length);
  return arg;
}

logLength('hello'); // 正确:string有length
logLength(10); // 错误:number没有length
2. 默认类型参数

为泛型指定默认类型:

function createArray<T = string>(length: number, value: T): T[] {
  return Array(length).fill(value);
}

const strArray = createArray(3, 'x'); // string[]
const numArray = createArray<number>(3, 10); // number[]
3. 多类型参数
function pair<T, U>(first: T, second: U): [T, U] {
  return [first, second];
}

const result = pair('age', 25); // [string, number]

典型应用场景

  1. 通用数据结构:如数组、栈、队列等
  2. 工具函数:如数组排序、过滤等不依赖具体类型的操作
  3. API响应处理:统一处理不同类型的接口返回数据
  4. 组件封装:React/Vue等框架中的可复用组件

泛型命名约定

  • T:Type(表示类型)
  • K:Key(表示对象的键类型)
  • V:Value(表示对象的值类型)
  • E:Element(表示元素类型)

这些只是约定,实际可以使用任何有效名称。

### 软件开发中的两种或概念 在软件开发领域,是一种重要的编程特性,旨在提高代码的灵活性、可重用性和安全性。以下是两种常见的或概念: #### 1. **基于类的延迟绑定** 这种的核心理念在于将具体的类定义推迟到实际使用阶段。通过这种方式,开发者可以在编写通用算法时无需提前指定具体的数据类,从而实现更高的代码复用率。 例如,在C#中,允许程序员声明一个类或方法时不立即确定其内部使用的数据类[^2]。只有当客户端代码实例化这个类或者调用该方法时,才会提供确切的类信息。这种方法不仅增强了代码的安全性,还减少了重复编码的工作量。 ```csharp public class GenericList<T> { private T[] items; public void Add(T item) { // 添加逻辑... } } ``` 在此示例中,`T` 是一种占位符,表示任何可能的具体类将在稍后的实例化过程中被替换掉。 #### 2. **子类关系与协变/逆变** 另一种的重要概念涉及子类之间的兼容性规则——即所谓的协变(covariance)和逆变(contravariance)。这一机制使得某些情况下可以更自由地处理继承层次结构内的对象转换问题。 以仓颉语言为例,它支持复杂的子类关系研究[^1]。这意味着如果存在两个类 `A` 和 `B` 并且 `B` 继承自 `A` ,那么对于某个接受 `IEnumerable<A>` 的函数来说,传入一个实现了 `IEnumerable<B>` 的集合也是合法的操作。这体现了系统的强大表达能力及其带来的额外便利之处。 ```java // Java 中的一个简单例子展示 List<? extends Number> 协变情况 void processNumbers(List<? extends Number> numbers) {} processNumbers(new ArrayList<Integer>()); processNumbers(new ArrayList<Double>()); ``` 以上代码片段展示了如何利用Java里的通配符(`?`)加上上下界约束来体现间的子类关联性质。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一池勺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值