TS泛型

79 阅读3分钟

一、类型参数

在开发中如果我们将参数类型写死的话就会发现满足这种类型就无法满足另一种类型,因此我们可以这样写:让类型像函数一样做为参数传过去

//类型推导
function show<Type>(arg: Type): Type {
  return arg
}

const res = show<string>("测试")
const res1 = show(123)//这里使用了类型推导
console.log(res)
console.log(res1)

这种类型推导会更加精准,上例中const res1 = show(123)写法在函数中Type就相当推导成为字面量类型为123


function num<Type1, Type2>(name: Type1, age: Type2) {
  return name + ":" + age
}

const res = num<string, number>("测试", 123)
console.log(res)
const res1 = num<number, number>(1233, 123)
console.log(res1) 

这里可以传入多个类型

二、泛型接口

接口基础的使用方式

interface CType {
  name: string
  age: number
}

1.接口参数使用

这里T使用的自己命名

interface CType<T> {
  name: T
  age: number
}

const test: CType<string> = {
  name: "linxi",
  age: 12
}

const test3: CType<object> = {
  name: { name: "linxi" },
  age: 12
}

2.接口参数默认值

interface CType<T = string> {
  name: T
  age: number
}
const test: CType = {
  name: "linxi",
  age: 12
}
const test3: CType<object> = {
  name: { name: "linxi" },
  age: 12
}

三、泛型类

class Person<T = number> {
  x: T
  y: T
  constructor(x: T, y: T) {
    this.x = x
    this.y = y
  }
}

const res1 = new Person(1, 2)
const res2 = new Person<string>("5", "8")

和上文接口使用类似如果没有默认值同样会进行类型推导使用

四、泛型约束

允许你在泛型类或函数中限制泛型类型参数,使其必须符合特定的条件。这样可以确保在使用泛型时,所传入的类型满足某些要求,从而提高代码的类型安全性和灵活性。

// 定义一个接口来描述具有 `length` 属性的类型
interface HasLength {
  length: number;
}

// 使用泛型约束来要求泛型 `T` 必须符合 `HasLength` 接口
function getLength<T extends HasLength>(obj: T): number {
  return obj.length;
}

// 使用示例
const str = "Hello, TypeScript!";
const arr = [1, 2, 3, 4, 5];
const objWithLength = { length: 10 };
const objWithoutLength = { name: "John" };

console.log(getLength(str));  // 输出 18,因为字符串长度为 18
console.log(getLength(arr));  // 输出 5,因为数组长度为 5
console.log(getLength(objWithLength));  // 输出 10,因为对象有 `length` 属性并且值为 10
// 下面的代码将产生一个类型错误,因为 `objWithoutLength` 缺少 `length` 属性
// console.log(getLength(objWithoutLength));

keyof

用于获取对象类型的键(即属性名)的联合类型。用于多种场景,例如类型约束、索引访问、函数参数等,以提高代码的类型安全性和灵活性

这里用在泛型约束

type Person = {
  name: string;
  age: number;
  city: string;
};
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

const person: Person = {
  name: "Alice",
  age: 30,
  city: "New York",
};

const getName: string = getProperty(person, "name"); // 正确,name 的类型为 string
const getAame: number = getProperty(person, "age"); // 正确,age 的类型为 number
// const invalidKey = getProperty(person, "salary"); // 错误,"salary" 不是 Person 类型的属性
console.log(getName)//Alice

五、映射类型

根据现有类型创建新类型。通过遍历现有类型的属性并在每个属性上进行操作来实现这一点,使得可以生成新的类型,例如将属性类型修改为可选、只读或者创建新的属性等操作

1.基本语法

type NewType = {
  [Property in keyof OldType]: NewPropertyType;
};
  • OldType 是要进行映射的原始类型。
  • PropertyOldType 中的每个属性名称。
  • keyof OldType 获取了 OldType 中所有属性的联合类型。
  • NewPropertyType 是根据 OldType 中的属性进行映射后的新类型。
type Person = {
  name: string;
  age: number;
};

type PersonPartial<T> = {
  [P in keyof T]: T[P];
};

type newPerson = PersonPartial<Person>

// newPerson 的类型为 { name?: string; age?: number; }

2. 修饰符只读映射类型

//可选属性
type PersonPartial<T> = {
  readonly [P in keyof T]?: T[P];
};

readonly为只读属性

-示例作用,?修饰符前面再加修饰符-

image.png

练习

ghaiklor.github.io/type-challe…

github.com/type-challe…