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

TypeScript中如何基于对象自身属性定义类型解决循环引用问题

解决方案

核心问题说明

你遇到的循环引用问题本质是TS类型系统不支持「在约束泛型参数结构的同时,读取该泛型参数的属性反过来约束自身」,TS需要先确定泛型的完整结构才能读取内部属性,二者形成了推导死锁。

基础示例实现

TS没有原生的self关键字指代正在定义的类型,你可以通过泛型函数的自动推导实现类似效果:

type X<T> = T extends 'a' ? 'a' : 'b'
function defineX<T extends string>(val: X<T>) {
  return val
}
// 自动校验值合法
const x = defineX('a') // 合法
const y = defineX('c') // 合法,会被推导为'b'类型

实际Questionnaire场景实现

推荐的实现思路是先定义所有合法的Question联合类型,再通过泛型函数自动推导约束,完全避免循环引用:

  1. 先定义所有Question类型的集合
// 可根据业务扩展任意Question类型
type BooleanQuestion = { type: 'boolean', required?: boolean, label: string }
type TextQuestion = { type: 'text', maxLength?: number, label: string }
type SelectQuestion = { type: 'select', options: string[], label: string }
type Question = BooleanQuestion | TextQuestion | SelectQuestion
  1. 定义泛型工具函数用于生成Questionnaire
function defineQuestionnaire<T extends Record<string, Question>>(config: T) {
  return config
}
  1. 直接使用即可自动校验每个Question的类型匹配
const myQuestionnaire = defineQuestionnaire({
  isAgree: {
    type: 'boolean',
    required: true,
    label: '是否同意用户协议'
  },
  nickname: {
    type: 'text',
    maxLength: 16,
    label: '用户昵称'
  },
  gender: {
    type: 'select',
    options: ['男', '女', '保密'],
    label: '性别'
  }
})

如果需要单独使用Questionnaire泛型类型,可以用Extract工具类型实现:

type Questionnaire<T extends Record<string, { type: Question['type'] }>> = {
  [K in keyof T]: Extract<Question, { type: T[K]['type'] }>
}

// 显式声明类型使用
type MyQuestionnaire = Questionnaire<{
  isAgree: { type: 'boolean' },
  nickname: { type: 'text' }
}>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 13:54:01