Reputation: 283313
I've got a function defined as:
export function useSubmitHandler(url: string, data: Json): [FormEventHandler<HTMLFormElement>, boolean] {}
Where Json
is:
type JsonPrimitive = string | number | boolean | null | undefined
interface JsonMap extends Record<string, JsonPrimitive | JsonArray | JsonMap> {}
interface JsonArray extends Array<JsonPrimitive | JsonArray | JsonMap> {}
export type Json = JsonPrimitive | JsonMap | JsonArray
If I try to call it with an arbitrary interface though, I get an error:
TS2345: Argument of type 'Fee' is not assignable to parameter of type 'Json'.
Type 'Fee' is not assignable to type 'JsonMap'.
Index signature is missing in type 'Fee'
But if I call it with that same object but spread like {...store.data}
then the error goes away.
How can I type useSubmitHandler
properly so that it will accept any object that is JSON stringifyable?
I think the Json
type is correct, but it needs something more to allow passing arbitrary types into the function.
Fee
is:
interface Fee {
id: number|null;
name: string;
type: string;
amount: string;
default: number;
company_id: number;
deleted_at?: any;
active: number;
fee_or_discount: string;
}
Of course, I'd like this to work with any type.
Upvotes: 4
Views: 1550
Reputation: 24194
Json
typetype JsonPrimitive = string | number | boolean | null;
type JsonMap = {
[key: string]: JsonPrimitive | JsonMap | JsonArray;
}
type JsonArray = Array<JsonPrimitive | JsonMap | JsonArray>;
type Json = JsonPrimitive | JsonMap | JsonArray;
Fee
interfaceinterface Fee {
[property: string]: any;
id: number|null;
name: string;
type: string;
amount: string;
default: number;
company_id: number;
deleted_at?: any;
active: number;
fee_or_discount: string;
}
useSubmitHandler(Router.route('fees.store')!, store.data as {[property: string]: any})
TypeScript GitHub issue Please provide a json
basic type #1897
Upvotes: 4
Reputation: 42288
One possible way to handle this is to wrap store.data
in a function which applies an index signature.
const indexed = <T extends {}>(obj: T): T & {[key: string]: never} => obj;
This function returns the same object that it was given but adds additional typescript information. We keep all of the values of the previously known type T
intact, but add an index signature {[key: string]: never}
which tells typescript that any keys other than those in the type cannot be anything other than undefined.
You can call your handler like this
useSubmitHandler(url, indexed(store.data))
The other option is to change your definition of Json
such that it doesn't have the index signature, which comes from using Record
. But I'm assuming that would be less desirable since (I think) you would have to broaden what's allowed.
Upvotes: 0