This is an extension of Typescript: interface that extends a JSON type
Given a JSON type like:
type JSONValue =
| string
| number
| boolean
| null
| JSONValue[]
| {[key: string]: JSONValue}
I'd like to find a way to tell typescript that interfaces that match the JSONType should be auto-casted when passed into functions that accept the JSONType. For example:
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'});
This currently fails with:
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'.
even though analytically we know that the passed in foo is a JSON compatible type.
Playground here
Is there a way to get typescript to recognize that this interface is in fact also JSON?
There are multiple issues within your implementation currently. You are trying to type the function
wrapas if it accepts a functionfnwhich may have arbitraryJSONValue[]data passed into it. But then you are passing inbar, a function which only acceptsFoo. To fix this, we can makewrapgeneric overTwhereTrepresents the parameters offn. We would then typeargsto be of typeTtoo, so that we can passargstofnsafely.Notice how I made
argsa spread parameter which it was not before. We don't wantargsto be a tuple type, as you don't pass a tuple to the function when calling it.But this will still not work.
Foois currently aninterfacewhich don't have implicit index signatures (see #15300). Aninterfacecan not fulfill the{[key: string]: JSONValue}constraint due to this missing implicit index signature. The only workaround we have without widening theJSONValuetype is to convertFooto be atype.Playground