1

I have this code:

export class JsonSerializable {
    toJson(): any {
        const jsonConvert = new JsonConvert();
        jsonConvert.valueCheckingMode = ValueCheckingMode.ALLOW_NULL;
        return jsonConvert.serialize(this);
    }

    static fromJson<T extends JsonSerializable>(data: any): T {
        const jsonConvert = new JsonConvert();
        jsonConvert.valueCheckingMode = ValueCheckingMode.ALLOW_NULL;

        return jsonConvert.deserializeObject(data, T) as T;
    }
}

deserializeObject() is defined as:

deserializeObject<T>(jsonObject: any, classReference: {
        new (): T;
    }): T;

I don't quite understand how I can declare my class to accept this without getting the "'T' only refers to a type, but is being used as a value here" error.

1 Answer 1

3

Your clue is in the definition of deserializeObject. You can't use a type in an expression. Types are erased after compilation T will not exist at runtime. That is why deserializeObject has a second parameter that takes in the class as a constructor signature (the classReference parameter).

You can do the same, and take the class as an extra parameter:

export class JsonSerializable {
    toJson(): any {
        const jsonConvert = new JsonConvert();
        jsonConvert.valueCheckingMode = ValueCheckingMode.ALLOW_NULL;
        return jsonConvert.serialize(this);
    }

    static fromJson<T extends JsonSerializable>(data: any, classReference: {
        new (): T;
    }): T {
        const jsonConvert = new JsonConvert();
        jsonConvert.valueCheckingMode = ValueCheckingMode.ALLOW_NULL;

        return jsonConvert.deserializeObject(data, classReference);
    }
}

class MyClass extends JsonSerializable {
    public f = ""
}

let a = JsonSerializable.fromJson({}, MyClass); // a is MyClass

Or if you don't mind invoking fromJson on the class that you want deserialize, you can use this (with an appropriate type annotation on for the this parameter):

export class JsonSerializable {
    toJson(): any {
        const jsonConvert = new JsonConvert();
        jsonConvert.valueCheckingMode = ValueCheckingMode.ALLOW_NULL;
        return jsonConvert.serialize(this);
    }

    static fromJson<T extends JsonSerializable>(this: new () => T, data: any): T {
        const jsonConvert = new JsonConvert();
        jsonConvert.valueCheckingMode = ValueCheckingMode.ALLOW_NULL;

        return jsonConvert.deserializeObject(data, this);
    }
}

class MyClass extends JsonSerializable {
    public f = ""
}

let a = MyClass.fromJson({}); // a is MyClass
Sign up to request clarification or add additional context in comments.

1 Comment

Amazing! I had no idea you could use "this" in a static method like that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.