Typescript:将接口作为参数传递给需要JSON类型的函数

57hvy0tb  于 2022-11-30  发布在  TypeScript
关注(0)|答案(1)|浏览(343)

这是Typescript: interface that extends a JSON type的扩展
给定如下JSON类型:

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

我想找到一种方法告诉typescript,当与JSONType匹配的接口被传递到接受JSONType的函数时,它应该被自动转换。

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

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

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

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

当前此操作失败,原因是:

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'.

即使通过分析我们知道传入的foo是JSON兼容类型。
这里是Playground
有没有办法让typescript识别出这个接口实际上也是JSON?

eqqqjvef

eqqqjvef1#

您的实作目前有多个问题。您尝试输入函式wrap,就好像它会接受函式fn,而该函式可能会传入任意JSONValue[]数据。但是您会传入bar,而该函式 * 只 * 接受Foo。若要修正此问题,我们可以使wrapT上泛型化,其中T表示fn的参数。然后,我们将args类型也输入为T,以便可以安全地将args传递给fn
注意我是如何将args作为一个 *spread参数 * 的,我们不希望args是一个元组类型,因为在调用它时,你不会将元组传递给函数。

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

但是这仍然不起作用。Foo当前是一个没有隐式索引签名的interface(请参阅#15300)。interface无法满足{[key: string]: JSONValue}条件约束,因为缺少这个隐含索引签章。唯一不需要扩大JSONValue型别的解决方法是将Foo转换为type

type 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'});

Playground

相关问题