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

TypeScript中如何让泛型Handler接受含指定层级类型的对象?

TypeScript泛型约束问题:让Handler接受含特定层级结构的类型

作为之前问题的后续,我编写了如下代码:

interface SubThing {
  name: string;
}

interface Thing {
  subThing: SubThing; // 或UpperThing中其他SubThing类型的属性
}

interface UpperThing {
  thing: Thing
}

interface ThingMapA {
  map: { thing: { subThing: { name : 'subThing name' } } };
}
interface ThingMapB {
  map: { thing: { otherThing: { name : 'subThing name' } } };
}

class Handler<T extends Record<keyof T, Record<keyof T, Thing>>> {}

const handler = new Handler<ThingMapA>(); // 报错
const handler = new Handler<ThingMapB>(); // 报错

我希望Handler能接受任何包含至少一个UpperThing类型属性(且该UpperThing至少包含一个Thing类型属性)的类型,但当前ThingMap无法被识别,会触发报错,请问有什么解决建议?


以下是基于某方案的另一个示例:

interface SubThing {
  name: string;
}

interface Thing {
  subThing: SubThing;
}

interface UpperThing {
  thing: Thing
}

interface ThingMapA {
  map: { thing: { subThing: { name: 'subThing name' } } };
}

interface ThingMapB {
  map: { otherThing: { subThing: { name: 'subThing name' } } };
}

interface ThingMapC {
  map: { thing: { otherSubThing: { name: 'subThing name' } } };
}

interface ThingMapD {
  map: { otherThing: { otherSubThing: { name: 'subThing name' } } };
}

class Handler<T extends { [K in keyof T]: { [P in keyof T[K]]: Thing } }> { }

const handlerA = new Handler<ThingMapA>(); // 正常
const handlerB = new Handler<ThingMapB>(); // 正常
const handlerC = new Handler<ThingMapC>(); // 报错
const handlerD = new Handler<ThingMapD>(); // 报错

问题分析

原代码中的泛型约束逻辑不符合需求:

  1. 初始约束Record<keyof T, Record<keyof T, Thing>>要求T的每个属性对象的键必须和T的键完全一致,这和需要的层级结构不匹配。
  2. 第二个示例的约束{ [K in keyof T]: { [P in keyof T[K]]: Thing } }要求T的每个属性下的所有子属性都是Thing类型,而需求是至少一个子属性为Thing类型,因此无法适配ThingMapC/D这类场景。

解决方案

根据需求,我们需要先定义类型判断逻辑,再约束Handler的泛型参数:

方案1:适配任意SubThing类型属性的Thing

如果你的Thing允许任意属性名对应SubThing类型(符合注释中“其他SubThing类型的属性”的描述),可以这样实现:

interface SubThing {
  name: string;
}

// 定义Thing:任意包含至少一个SubThing类型属性的对象
type Thing = Record<string, SubThing>;

// 判断类型U是否包含至少一个Thing类型的属性
type HasAtLeastOneThing<U> = 
  Exclude<{ [P in keyof U]: U[P] extends Thing ? P : never }[keyof U], never> 
  extends never ? false : true;

// Handler约束:T中至少存在一个属性是UpperThing(包含至少一个Thing类型属性)
class Handler<T extends Record<string, unknown> & (HasAtLeastOneThing<T[keyof T]> extends true ? unknown : never)> {}

// 测试案例
interface ThingMapA {
  map: { thing: { subThing: { name : 'subThing name' } } };
}
interface ThingMapB {
  map: { thing: { otherThing: { name : 'subThing name' } } };
}
interface ThingMapC {
  map: { thing: { otherSubThing: { name : 'subThing name' } } };
}
interface ThingMapD {
  map: { otherThing: { otherSubThing: { name : 'subThing name' } } };
}

const handlerA = new Handler<ThingMapA>(); // 正常
const handlerB = new Handler<ThingMapB>(); // 正常
const handlerC = new Handler<ThingMapC>(); // 正常
const handlerD = new Handler<ThingMapD>(); // 正常

方案2:严格要求Thing包含subThing属性

如果你的Thing必须严格包含subThing属性,只需调整Thing的定义:

interface SubThing {
  name: string;
}

interface Thing {
  subThing: SubThing;
}

// 判断类型U是否包含至少一个Thing类型的属性
type HasAtLeastOneThing<U> = 
  Exclude<{ [P in keyof U]: U[P] extends Thing ? P : never }[keyof U], never> 
  extends never ? false : true;

// Handler约束:T中至少存在一个属性是UpperThing(包含至少一个Thing类型属性)
class Handler<T extends Record<string, unknown> & (HasAtLeastOneThing<T[keyof T]> extends true ? unknown : never)> {}

// 测试案例
interface ThingMapA {
  map: { thing: { subThing: { name : 'subThing name' } } };
}
interface ThingMapB {
  map: { thing: { otherThing: { name : 'subThing name' } } };
}

const handlerA = new Handler<ThingMapA>(); // 正常
const handlerB = new Handler<ThingMapB>(); // 报错(因为otherThing不是Thing类型)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 15:45:06