2026-01-24

4 阅读2分钟

记录每天自我学习转前端的碎碎念,仅作加强记忆的笔记和自我监督打卡使用。

泛型

通常在定义函数或者接口时,如果一个参数或者属性的数据类型是明确的,比如说是string或者number,则定义时很容易

function add(a:number, b:number):number {
 return a+b;
}
interface Person {
  name : string
}

但是如果一个参数或者属性的数据类型并不清楚,我不知道是string还是number,这种场景通常使用泛型来解决,泛型及只有使用的时候才确定其类型

const printFun = <T>(value: T): T => {
  console.log(value);
  return value;
};

printFun(233);

// 可以设置默认值
interface Person<T = string> {
  address:T
}

function demo<T>(person:Person<T>) {
   console.log(person.address)
}
demo<string>({address:'中国'})
demo({address:'中国'}) // 也可以

note:这里由于参数person是:Person<T>类型,则表示函数demo是一个泛型函数,所以也需要定义demo<T>

泛型还可以通过extends进行约束扩展

// dmeo1
interface Person<J, K> {
  name: J;
  age: K;
}
const printFun = <T extends Person<string, number>, S>(
  person: T,
  msg: S
): S => {
  console.log(person.age);
  console.log(person.name);
  return msg;
};
printFun({ name: "sunny", age: 18 }, "success");

// dmeo2
function logLength<T extends { length: number }>(arg: T): T {
  console.log(arg.length);
  return arg;
}
logLength("string"); // 正确
logLength({ length: 5 }); // 正确
logLength(123); // 错误:数字没有length属性

// demo3(和demo2效果一致)
interface Lengthwise {
  length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
  console.log(arg.length);
  return arg;
}

注意:静态成员不能使用类的类型参数

class GenericClass<T> {
  static defaultValue: T;  // 错误:静态成员不能使用类的类型参数
}

TypeScript内置了多个实用的泛型工具类型:

1.Partial 是一个内置工具类型,用于将一个对象类型的所有属性变为可选属性。它通过映射类型实现,为每个属性添加 ? 修饰符,使其变为可选属性

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

// 使用 Partial 创建所有属性可选的新类型
type PartialUser = Partial<User>;
/* 等价于:
type PartialUser = {
  id?: number;
  name?: string;
  email?: string;
}
*/

2.Readonly: 使所有属性变为只读

type ReadonlyUser = Readonly<User>;

3.Record: 键值对映射

type UserPreview = Record<"id" | "name" | "email", string>;

项目应用1

interface ApiResponse<T> {
  data: T;
  status: number;
  message: string;
}

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

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

fetchData<User>("/api/user").then(response => {
  console.log(response.data.name); // 类型安全
});

项目应用2

interface User {
  id:string,
  name:string
}

interface Repository<T, ID> {
  findById(id: ID): Promise<T | null>;
  save(entity: T): Promise<T>;
  findAll(): Promise<T[]>;
}

class UserRepository implements Repository<User, number> {
  findById(id: number): Promise<User> {
  return Promise.resolve({
    id:'12',
    name:'李白'
 })
}

save(entity: User): Promise<User> {
  return Promise.resolve({
    id:'12',
    name:'李白'
  })
}

findAll(): Promise<User[]> {
  return Promise.resolve([{
    id:'12',
    name:'李白'
  }])
 }
}