You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript中如何限制方法泛型为对象且兼容interface与type?

解决方案

你可以通过Record<keyof T, unknown>作为泛型约束实现需求,完美兼容interface、type定义的对象类型,同时全程不引入any:

// 修改后的doSomething实现
function doSomething<T extends Record<keyof T, unknown>>(obj: T) {
  Object.entries(obj).forEach(([key, value]) => {
    console.log(key, value)
  })
}

// 配套的自定义Hook也需要加上相同的泛型约束,避免入参不符合要求
function useCustomHook<T extends Record<keyof T, unknown>>(initialData: T[]) {
  const [changes, setChanges] = React.useState<T[]>([])
  // 从changes中获取元素调用方法示例
  changes.forEach(item => doSomething(item))
}

实现原理

  • 自动过滤非对象类型:string、number、boolean、null、undefined等基本类型均不满足Record<keyof T, unknown>的约束,传入时会直接抛出TS错误
  • 兼容interface和type:keyof T会自动推导目标类型的所有属性键,无论你用type还是interface定义对象类型,都不会出现「索引签名缺失」的报错
  • 类型安全:全程没有使用any类型,所有属性值的类型都会被推导为unknown,符合严格类型校验要求

校验效果验证

你要求的异常调用场景都会触发TS报错:

doSomething('test') // 报错
doSomething(12) // 报错
doSomething(undefined) // 报错

合法调用场景均可正常通过校验:

// Type类型定义
type ExampleType = {
  property1: number,
  property2: string
}
// Interface定义
interface ExampleInterface {
  property1: number;
  property2: string;
}

doSomething({}) // 通过
doSomething({ property1: 12, property2: 'string'}) // 通过
doSomething<ExampleType>({ property1: 12, property2: 'string'}) // 通过
doSomething<ExampleInterface>({property1: 12, property2: 'string'}) // 通过

可选优化(禁止传入数组)

如果需要额外禁止数组类型的入参,可以把泛型约束调整为:

function doSomething<T extends Record<keyof T, unknown> & { length?: never }>(obj: T) {
  // 实现逻辑不变
}

该约束会过滤掉带length属性的数组类型,仅允许普通对象传入。

内容的提问来源于stack exchange,提问作者Martin Hofhanzl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 01:24:03