13

Lets say I have a class C and an Instance of Object O (from JSON).

class C {
  str:string;
  num:number;
}

var o = JSON.parse ("{\"num\":123, \"str\":\"abc\"}");

Is there a way I can assign/initialize an instance of C with o and it checks for undefined values as well as for the type WITHOUT doing it by myself in a copy-constructor/function?

I'd like to get an error or exception if a value is missing/undefined or the type does not match.

Thanks!

2
  • Couldn't you make the class C implement some interface? If I understand your issue correctly, this would ensure the values are there and that the types are correct. As for the error, your solution would fail to build if not valid. Not sure if this would help your problem or not Commented Sep 30, 2017 at 10:09
  • 1
    The problem is that the compiler cannot infer what JSON.parse will return, and therefore you will not get error checking at compile time. It's important to know where the JSON comes from and if you can be sure or not what it will contain. If not, you will need runtime error checking. Commented Sep 30, 2017 at 10:35

5 Answers 5

22

You can use Object.assign:

class C {
    str:string;
    num:number;
}
var o = JSON.parse("{\"num\":123, \"str\":\"abc\"}");
const instance:C = Object.assign(new C(), o);
Sign up to request clarification or add additional context in comments.

Comments

9

I landed here wanting to create a class instance from an object literal. Object.assign() works but it isn't type safe. Of course, if you have JSON source that's expected but I just wanted to instantiate a class with a known state.

From the TypeScript docs, a class also acts as a type. Thus, the following will work:

class C {
    str: string;
    num: number;

    constructor(source: Partial<C>) {
        Object.assign(this, source);
    }
}

// Ok - all properties
const c1 = new C({
    num: 123,
    str: "abc"
});

// Ok - only some of the properties
const c1 = new C({
    num: 123,
});

// Error: unknown property `unexpectedPropertyName`
const c2 = new C({
    num: 123,
    unexpectedPropertyName: "abc"
});

Comments

3

Here is an example of creating objects directly, which will give you live error checking. The problem with JSON.parse it that the compiler will not check at compile time what it returns. If you work with unknown live data you will have to write some error check manually.

interface Obj {
  str: string
  num: number
}

class C {
  constructor(o:Obj) { 

  }
}

var o = {test:43, str:"abc"}
var p = {num:43, str:"abc"}

var instanceOne = new C(o) // not allowed
var instanceTwo = new C(p) // allowed

4 Comments

This is the case because your objects o and p are defined at compile-time. And thats not the case with JSONs dynamic strings. I did not ask for compile-time checks of runtime-information. I would also be happy with a runtime check that I do not need to implement by myself.
Since the whole type system does not exist at runtime, I see no way to check the type without programming your checks manually. Well, you could use try catch.... :)
I'm not sure why you've answered with that code. Your original comment - "The compiler cannot infer what JSON.parse will return, and therefore you will not get error checking at compile time" is correct. Its that extra step to extract the type information and move the problem the run-time domain that is pertinent.
Ok, but when is your JSON data loaded? In most cases, an app loads JSON at runtime.
2

What you are asking for is a JSON schema validator. The validation must be ran in runtime. Check https://github.com/epoberezkin/ajv for a complete JSON schema validator or https://www.npmjs.com/package/js-schema for a simpler one.

2 Comments

and you can extract the schema from your typescript source: github.com/YousefED/typescript-json-schema
A JSON Schema Validator does not fully answer what they ask for, because the object will still not be an instance of C. If you add a method to a class, and deserialize an object from JSON, it doesn't have that method - because it's not a Duck, it's Duck-like.
0

Typescript is a type system that runs at compile time, what you are asking is therefore impossible.

You could have a look at type guards and maybe use them to provide type inference inside a conditional block of some kind of parse function.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.