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.
    – Kokodoko
    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);
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"
});
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
  • 1
    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.
    – chris01
    Commented Sep 30, 2017 at 17:56
  • 1
    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.... :)
    – Kokodoko
    Commented Sep 30, 2017 at 21:32
  • 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. Commented Oct 2, 2017 at 21:11
  • Ok, but when is your JSON data loaded? In most cases, an app loads JSON at runtime.
    – Kokodoko
    Commented Oct 3, 2017 at 11:59
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
  • 1
    and you can extract the schema from your typescript source: github.com/YousefED/typescript-json-schema Commented Oct 2, 2017 at 21:16
  • 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.
    – ANeves
    Commented Jul 25, 2023 at 10:58
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.

Not the answer you're looking for? Browse other questions tagged or ask your own question.