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

TypeScript:如何拓宽JSONValue类型以兼容现有接口?

如何拓宽TypeScript的JSONValue类型以支持接口传递

背景

这是两个TypeScript问题的延伸:先是探讨与JSON类型之间的类型转换,再延伸到向期望JSON类型的函数传递接口的问题,核心都围绕标准JSONValue类型展开:

type JSONValue = 
 | string
 | number
 | boolean
 | null
 | JSONValue[]
 | {[key: string]: JSONValue}

问题重现

此前结论表明,无法直接将interface传递给期望JSONValue的函数,如下代码会报错:

interface Foo {
  name: 'FOO',
  fooProp: string
}

const bar = (foo: Foo) => { return foo }

const wrap = <T extends JSONValue[]>(
  fn: (...args: T) => JSONValue, 
  ...args: T
) => {
  return fn(...args);
}

wrap(bar, { name: 'FOO', fooProp: 'hello'});

报错原因是TypeScript不认为interface Foo可以赋值给JSONValue——尽管从结构上看Foo完全符合JSON规范,这是因为TypeScript将具名对象类型(如接口)和索引签名对象类型({[key: string]: JSONValue})视为不兼容的类型。

解决方案:拓宽JSONValue类型

要让JSONValue兼容所有符合JSON结构的接口,我们需要修改JSONValue的定义,让它不仅包含索引签名对象,还能接受所有属性值均为JSONValue的具名对象类型。

基础拓宽方案

修改后的JSONValue定义如下:

type JSONValue = 
  | string
  | number
  | boolean
  | null
  | JSONValue[]
  | { [key: string]: JSONValue }
  | { [K in keyof any]: JSONValue };

新增的{ [K in keyof any]: JSONValue }分支覆盖了所有具名对象类型(包括接口),只要这些对象的所有属性值都属于JSONValue类型。这样TypeScript就会将符合结构的接口视为JSONValue的子类型,从而允许将接口传递给期望JSONValue的函数。

严格约束方案

如果需要更严格地限制只接受符合JSON规范的对象(排除Date、Map等非JSON对象),可以结合递归条件类型进一步约束:

type IsJSONCompatible<T> =
  T extends string | number | boolean | null ? true :
  T extends Array<infer U> ? IsJSONCompatible<U> :
  T extends { [key: string]: infer V } ? IsJSONCompatible<V> :
  false;

type JSONValue = 
  | string
  | number
  | boolean
  | null
  | JSONValue[]
  | { [key: string]: JSONValue }
  | (T extends object ? IsJSONCompatible<T> extends true ? T : never : never);

这种方式会自动过滤掉属性值不符合JSON规范的对象,同时兼容所有结构合法的接口。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 23:50:28