This is an extension of Typescript: passing interface as parameter for a function that expects a JSON type (asking about passing interfaces to JSON typed functions), which in turn is an extension of Typescript: interface that extends a JSON type (asking about casting to/from JSON types)
These questions relate to a JSON Typescript type:
type JSONValue =
| string
| number
| boolean
| null
| JSONValue[]
| {[key: string]: JSONValue}
In Typescript: passing interface as parameter for a function that expects a JSON type, the final answer indicates that it is not possible to pass an interface to a function that expects a JSON value. In particular, the following code:
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'});
fails because the interface Foo
cannot be assigned to JSONValue
even though analytically it is easy to recognize that the cast should be fine.
see playground, as well as https://github.com/microsoft/TypeScript/issues/15300
The previous answer stated:
The only workaround we have without widening the JSONValue type is to convert [interface] Foo to be a type.
In my case, I can modify the JSONValue type but cannot easily modify all of the relevant interfaces. What would widening the JSONValue type entail?
CodePudding user response:
If you use a separate generic for the return type (which also extends JsonValue
, then you won't have a type compatibility issue, and you can also infer a more narrow return type:
function wrap <A extends JsonValue[], T extends JsonValue>(
fn: (...args: A) => T,
...args: A
): T {
return fn(...args);
}
const result = wrap(bar, { name: 'FOO', fooProp: 'hello'}); // ok