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

如何让TypeScript识别符合JSON类型的接口并自动适配函数参数?

如何让TypeScript识别接口属于兼容JSON的类型?

给定如下递归定义的JSON值类型:

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

场景是:我们定义了一个接口Foo、操作该接口的函数bar,还有一个接受JSONValue类型参数的wrap函数。调用wrap(bar, {name: 'FOO', fooProp: 'hello'})时,TypeScript会抛出类型不兼容错误:

Argument of type '(foo: Foo) => Foo' is not assignable to parameter of type '(...args: JSONValue[]) => JSONValue'.
  Types of parameters 'foo' and 'args' are incompatible.
    Type 'JSONValue' is not assignable to type 'Foo'.
      Type 'null' is not assignable to type 'Foo'.

尽管我们知道传入的参数完全符合JSON兼容结构,但TS无法自动识别接口Foo属于JSONValue的子类型。以下是几种可行的解决方式:

1. 用工具类型约束并断言类型

先定义一个工具类型,用来验证类型是否兼容JSONValue:

type IsJSONCompatible<T> = T extends JSONValue ? T : never;

之后在调用wrap时,通过类型断言明确告知TS:bar的参数和返回值都是兼容JSON的类型:

interface Foo {
  name: string;
  fooProp: string;
}

const bar = (foo: Foo): Foo => ({...foo});

function wrap(fn: (...args: JSONValue[]) => JSONValue, ...args: JSONValue[]): JSONValue {
  return fn(...args);
}

// 使用类型断言转换bar的类型
wrap(bar as (foo: IsJSONCompatible<Foo>) => IsJSONCompatible<Foo>, {name: 'FOO', fooProp: 'hello'});

2. 定义递归工具类型转换接口为JSON兼容类型

如果接口嵌套层级较深,可以用递归工具类型自动转换所有属性为JSON兼容类型:

type ToJSONCompatible<T> = 
  T extends JSONValue ? T :
  T extends object ? {[K in keyof T]: ToJSONCompatible<T[K]>} :
  never;

// 转换Foo为JSON兼容类型
type FooJSON = ToJSONCompatible<Foo>;

// 断言bar接受并返回FooJSON类型
wrap(bar as (foo: FooJSON) => FooJSON, {name: 'FOO', fooProp: 'hello'});

3. 结合类型守卫做运行时+编译时双重校验

如果需要更安全的校验,可以写一个类型守卫函数,在运行时验证输入是否符合Foo结构,同时让TS在编译时识别类型:

function isFoo(value: JSONValue): value is Foo {
  return (
    typeof value === 'object' && 
    value !== null && 
    typeof (value as Foo).name === 'string' && 
    typeof (value as Foo).fooProp === 'string'
  );
}

const input = {name: 'FOO', fooProp: 'hello'};
if (isFoo(input)) {
  // 此时TS已确认input是Foo类型,再通过断言传递给wrap
  wrap(bar as (foo: JSONValue) => JSONValue, input);
}

核心原因

TypeScript不会自动推断接口是JSONValue的子类型,因为JSONValue是递归联合类型,TS不会主动遍历接口的所有属性来验证其是否完全符合JSON结构。必须通过工具类型、断言或类型守卫,手动向TS声明接口的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.10 08:25:27