Qwertiy
Qwertiy

Reputation: 21510

Object can be parsed from json only

I want to specify type in that way, that its generic parameter should be an object that can be parsed from json. So no functions, no dates, no other kinds of values that can't be represented in json. How can I do that?

Example:

function get<T>(url: string): Promise<T> {
    return fetch(url).then(resp => resp.json())
}

interface Type1 {
    x: string;
}

interface Type2 {
    x: string;
    getX(): string;
}

interface Type3 {
    x: Date;
}

interface Type4 {
    x: {
        a: number[];
        b: { z: (string | null)[] };
    };
}

async function main() {
    var a = await get<Type1>("/")
    var b = await get<Type2>("/") // Want a error
    var c = await get<Type3>("/") // Want a error
    var d = await get<Type4>("/")
}

Upvotes: 4

Views: 149

Answers (1)

awarrier99
awarrier99

Reputation: 3855

Try creating an interface for your desired type that specifies a union of all valid types, like this:

interface IJson {
    [key: string]: number | string | boolean | Array<number | string | boolean | IJson | null> | IJson | null;
}

Edit: After some research, turns out TypeScript actually provides an example of exactly this on their docs. They recommend this:

type Json =
    | string
    | number
    | boolean
    | null
    | { [property: string]: Json }
    | Json[];

Edit 2: Check out my updated (from yours) sandbox that plays around with some of these things. Unfortunately, it doesn't seem possible to pass an interface argument to T unless the interface also has an index signature, something like { [key: string]: string }. You should be able to get around this by changing your interface to a type definition, like type Type1 = { x: string } which should then work just fine. I know it's not exactly what you were looking for but I'm not sure that there's currently (or ever will be) support for that in TypeScript.

Upvotes: 2

Related Questions