Skip to Content

Memberwise Constructor

In order for Codables to automatically handle your class, there is some convention you need to follow.

Codables can automatically handle classes that:

  • Have no constructor
  • Have a memberwise constructor

Other cases will require you to provide encode function that will return arguments matching the constructor of your class.

What is a memberwise constructor?

A memberwise constructor is a constructor that takes only one argument - an object with properties matching the structure of your class properties.

This is the same as eg Swift Codable structs constructors work.

// ✅ - this is a class with a memberwise constructor class MemberwiseClass { foo: string; bar: number; constructor(input: Pick<MemberwiseClass, "foo" | "bar">) { this.foo = input.foo; this.bar = input.bar; } } // ❌ - this class has some custom constructor logic // Still usable with Codables, but will need to provide instance => [foo, bar] function class NotMemberwiseClass { foo: string; bar: number; constructor(foo: string, bar: number) { this.foo = foo; this.bar = bar; } }

Constructor is optional and not required for @codableClass to work. Under the hood, Codables will automatically assign properties to the instance.

Constructor are here mostly for convenience, when you manually create your instances.

@codableClass TypeScript definition will automatically detect non-memberwise classes and require you to provide encode function.

// ❌ TypeScript will complain as this class has no memberwise constructor // You will have to provide `encode` to @codableClass decorator to make error go away @codableClass("User") class User { @codable() name: string; @codable() email: string; constructor(public name: string, public email: string) {} } // ✅ This works - constructor matches memberwise pattern @codableClass("User") class User { @codable() name: string; @codable() email: string; constructor(data: Pick<User, "name" | "email">) { this.name = data.name; this.email = data.email; } }

Memberwise and MemberwiseExclude helper types

In the example above, we used Pick<User, "name" | "email"> to create a type that matches the structure of your class properties.

It can quickly get verbose, especially if you have a lot of codable properties or methods.

You can use Memberwise and MemberwiseExclude types to create a type that matches the structure of your class properties, while always excluding methods.

Memberwise<User> will require every property to be present.

@codableClass("User") class User { @codable() name!: string; @codable() email!: string; someMethod() {} // All properties except methods constructor(data: Memberwise<User>) { Object.assign(this, data); } }

Memberwise<User, "someProperty"> will require only someProperty property to be present.

@codableClass("User") class User { @codable() name!: string; nonCodable!: string; anotherNonCodable!: number; yetAnotherNonCodable!: boolean; someMethod() {} // Only 'name' property (other properties are not codable) constructor(data: Memberwise<User, "name">) { Object.assign(this, data); } }

MemberwiseExclude<User, "nonCodable"> will require everything except nonCodable property to be present.

@codableClass("User") class User { @codable() name!: string; @codable() email!: string; @codable() age!: number; @codable() isAdmin!: boolean; @codable() createdAt!: Date; nonCodable: string; someMethod() {} // Everything except 'nonCodable' property constructor(data: MemberwiseExclude<User, "nonCodable">) { Object.assign(this, data); } }

Custom Constructor Handling

If your constructor doesn’t match the memberwise pattern, you need to provide a function that will return arguments matching the constructor of your class.

@codableClass("User", { encode: (user) => [user.name, user.email], }) class User { @codable() name: string; @codable() email: string; // Non-memberwise constructor constructor(name: string, email: string) { this.name = name; this.email = email; } }
Last updated on