一个困扰我许久的TypeScript定义问题

最近在使用TypeScript定义函数参数时,我遇到了一个难题,这让我感到困扰。我猜想这可能是因为我对TypeScript的掌握不够深入。虽然我问了无数次ChatGPT,但未能获得满意的解答。至今还没解决方案。今天我将这个问题分享出来,希望能听到大家的意见,看看是否有解决方案。

我在定义addComp函数时,设置了一个参数,该参数是一个数组。数组的每一项包含两个属性:type表示组件的类型,props包括组件的可配置属性。不同组件的props有共同的也有独特的属性,例如:

js 复制代码
  [
    {
      type: 'Input',
      props: {
        required: true,
        defaultValue: '默认值',
        placeholder: '请输入',
      },
    },
    {
      type: 'Select',
      props: {
        required: true,
        defaultValue: ['1'],
        placeholder: '请输入',
        options: [
          {
            label: '选项一',
            value: '1'
          }
        ]
      },
    },
  ]

我对以上数据做了如下的TypeScript。

ts 复制代码
// 定义 props 属性的基础接口
interface CompProps {
  required?: boolean;
  placeholder?: string;
}

// 定义特定控件类型的 props 接口
interface InputProps extends CompProps {
  defaultValue?: string;
}

interface SelectProps extends CompProps {
  defaultValue?: string[] | number[];
  options: Array<{ label: string, value: string }>;
}

type CompPropsMap = {
  Input: InputProps;
  Select: SelectProps;
};

// 定义组件类型的联合类型
type CompType = 'Input' | 'Select';

// 定义 AddCompParam 中每一项的接口
interface AddCompParam<T extends CompType> {
  type: T;
  props: CompPropsMap[T];
}

然而,在使用过程中发现了问题。例如,以下示例应该报错,但实际上并没有:

ts 复制代码
// 示例对象
const addCompParam: AddCompParam<CompType>[] =
  [
    {
      type: 'Input',
      props: {
        required: true,
        defaultValue: ['默认值'],// 这里应为string,错误地使用了string[]
        placeholder: '请输入',
        options: [],// 这是一个无关属性,不应存在于InputProps中
      },
    },
];

按理论来推动,此时应该会报错,但是实际不会报错。我尝试开启严格模式,重启TypeScript服务,还是不会报错。问 ChatGPT,得到的答复是

在您的例子中,AddCompParam 的定义是基于泛型的,因此 TypeScript 会根据传入的类型进行推断。由于 CompPropsMap 中的 InputPropsSelectProps 是通过继承和映射来定义的,TypeScript 可能没有对 props 的结构进行严格的检查。具体来说,props 是一个对象,TypeScript 在类型检查时可能会允许额外的属性存在于对象中,只要对象中包含了所需的属性。这就是为什么在 Inputprops 中添加了 options 属性,TypeScript 仍然不会报错。

我对上面的答复不是很满意。为了让TypeScript 能够报错,我换了一种定义方式

ts 复制代码
// 定义 props 属性的基础接口
interface CompProps {
    required?: boolean;
    placeholder?: string;
}

// 定义特定控件类型的 props 接口
interface InputProps extends CompProps {
    defaultValue?: string;
}

interface SelectProps extends CompProps {
    defaultValue?: string[] | number[];
    options: Array<{ label: string, value: string }>;
}

// 定义 AddCompParam 中每一项的接口
type AddCompParam = 
{ type: 'Input'; props: InputProps } | 
{ type: 'Select'; props: SelectProps };

然而,在实际使用过程中,我发现了另一个严重的问题:错误信息的提示并不准确。

ts 复制代码
// 示例对象
const addCompParam: AddCompParam[] =
  [
    {
      type: 'Input',
      props: {
        required: true,
        defaultValue: ['1'],
        placeholder: '请输入',
      },
    },
];

报错信息如下所示:

不能将类型{ required: true; defaultValue: string[]; placeholder: string; }分配给类型InputProps | SelectProps

类型 { required: true; defaultValue: string[]; placeholder: string; } 中缺少属性 options,但类型 SelectProps 中需要该属性。

这个错误提示令我困惑。虽然我明确将type设置为Input,问题显然出在propsdefaultValue类型上,但错误提示却显示缺少options属性。尽管我尝试补全了这个属性,错误提示改变了,但仍未指向defaultValue的类型问题。

ts 复制代码
// 示例对象

const addCompParam: AddCompParam[] =
  [
    {
      type: 'Input',
      props: {
        required: true,
        defaultValue: ['1'],
        placeholder: '请输入',
        options:[]
      },
    },
];

报错信息如下所示:

不能将类型{ type: "Input"; props: { required: true; placeholder: string; defaultValue: string[]; options: { label: string; value: string; }[]; }; }分配给类型AddCompParam

属性props的类型不兼容。

对象字面量只能指定已知属性,并且options不在类型InputProps中。

我再次询问 ChatGPT 得到的答复是

您遇到的错误提示是由于 TypeScript 处理联合类型时的类型推断机制。在您的代码中,AddCompParam 是一个联合类型,它可以是 InputSelect 类型。当 TypeScript 检查 addCompParam 数组中的对象时,它会尝试确保 props 属性符合 InputPropsSelectProps 的定义。
在您的示例中,您定义了一个 Input 类型的对象,但是在 props 中,您传递了一个 defaultValue 的值为 ['1'],这是一个字符串数组(string[]),而 InputProps 中的 defaultValue 应该是一个字符串(string)。因此,TypeScript 在尝试推断 props 的类型时,发现 defaultValue 的类型不匹配。
由于 props 的类型是 InputProps | SelectProps,TypeScript 会将 props 视为可能是 SelectProps 类型,因此它会检查 SelectProps 的所有必需属性,包括 options。这就是为什么您会看到提示缺少 options 属性。

目前我还不确定如何解决这个问题。如果按照下面的方式定义:

ts 复制代码
type AddCompParam = [ 
  { type: 'Input'; props: InputProps }, 
  { type: 'Select'; props: SelectProps }
];

这种定义方式似乎限制了addCompParam参数中每个项的固定位置,例如type: 'Select'必须位于addCompParam数组的第二个位置。这并不是我想要的效果。

我尝试了多种方式向ChatGPT描述这个问题,但是得到的回答都未能提供正确的解决方案。可能是我的问题描述不够清晰,导致ChatGPT无法完全理解问题的核心。

如果各位掘友有遇到过类似问题并找到了解决方案,恳请在评论区分享一下,非常感谢!

相关推荐
子兮曰4 小时前
Bun v1.3.14 深度解析:Image API、HTTP/3、全局虚拟存储与五十项变革
前端·后端·bun
kyriewen5 小时前
今天,百年巨头一次砍了9200人,而一个离职科学家的实话让全网睡不着觉
前端·openai·ai编程
问心无愧05135 小时前
ctf show web 入门42
android·前端·android studio
kyriewen5 小时前
老板逼我上AI,我偷偷在浏览器里跑LLaMA,省下20万API费
前端·react.js·llm
Beginner x_u6 小时前
前端八股整理(手写 02)|数组转树、数组扁平化、随机打乱一个数组
前端·数组·数组转树·数组扁平化
KaMeidebaby6 小时前
卡梅德生物技术快报|禽类成纤维细胞 FISH 实验:鸟类性别染色体基因定位技术实现与数据验证
前端·数据库·其他·百度·新浪微博
天若有情6736 小时前
前端高阶性能优化:跳出传统懒加载与预加载,基于用户行为做轻量预判加载
前端·性能优化
小小小小宇6 小时前
前端转后端:SQL 是什么
前端
张元清7 小时前
React Observer Hooks:7 种监听 DOM 而不写样板代码的方式
前端·javascript·面试
广州华水科技7 小时前
单北斗GNSS变形监测是什么?主要有怎样的应用与优势?
前端