timoxley
timoxley

Reputation: 5204

TypeScript: Infer class properties from constructor(options) or vice versa

I'm converting some JS to TS, something like this:

class User {
  constructor({ name, age }) {
    this.name = name
    this.age = age
  }
  // … + methods
}

I was hoping with TypeScript it would be able to infer the properties on User, or there would be some way to avoid duplicating the shape of the constructor options object shape and the class shape. However, my attempt of getting TypeScript to infer the class shape from the options did not work:

type UserOptions = {
  name: string
  age: number
}

class User {
  constructor(options: UserOptions) {
    this.name = options.name // Property 'name' does not exist on type 'User'.
    this.age = options.age // Property 'age' does not exist on type 'User'.
    // or Object.assign(this, options), neither works
  }
}

const user = new User({ name: 'Alice', age: 42 })

console.log(user.name, user.age) // Property 'name' does not exist on type 'User'.

https://www.typescriptlang.org/play?ssl=1&ssc=1&pln=16&pc=83#code/C4TwDgpgBAqgzhATgeTMAlgewHZygXigG8AoKKbAQwFsIAuKOYRdbAczKkrfooFdqAIyQkAviRIBjADaU4eeEmKdJOJoj6TgmRAApMaLLgaKUhtQEpl5csAAW6OADoqtAlAMY1LmtAD0flAACogGSKBQAOSuEJFQACaYEHjYmMBQEAAejuk4UKCQUaaRTpy2Ds7c0ISeRpU8UAHBoZCIEZFVcYnJFGkZ2Uwe2Png0JHFpTaNgTpQyIIAVhBaTnJw6GzYuvaOADQe5rgW+9gQ6PZKAO46ANZwnOLiUmrpfAiI7qeXsO+6RBS+BiRACC0nQkli+yqDAALAAmKCiCwSVS4TDSCBOaSYNi6N5IHy0fb4xCrHhWJohMJtEBRGJdJIpPpZHJDEaFcbvEpAA

I note that it's able to infer the shapes correctly if I use an object factory function instead of a class:

type UserOptions = {
  name: string
  age: number
}

function User(options: UserOptions) {
  return Object.assign({}, options)
}

const user = User({ name: 'Alice', age: 42 })

console.log(user.name, user.age)

https://www.typescriptlang.org/play?#code/C4TwDgpgBAqgzhATgeTMAlgewHZygXigG8AoKKbAQwFsIAuKOYRdbAczKkrfooFdqAIyQkAviRIAzPtgDGGHLASIAYtgAUmNFlwN4SVAtwBKYp0QRgfRNijJBAKwjyAdJThx0bDUVEAaKC0jOGMxCVkcJig+ZQIlJDV1IgoaXgByAEEAG3RZCDSA7l4AFgAmKFFQkgjcTCyIFyzMNnUYpBcqWgC2xDceYyA

Is there some way to tell TypeScript to infer the properties on a class User from UserOptions, or vice-versa?

I feel like I shouldn't need to manually duplicate each property definition from UserOptions onto User.

Something like the first example in this blog post: https://fettblog.eu/low-maintenance-types-typescript/

Upvotes: 1

Views: 409

Answers (1)

Here you have other solution:

interface User {
  name: string
  age: number
}

class User {
  constructor(options: User) {
    this.name = options.name
    this.age = options.age 
  }
}

const user = new User({ name: 'Alice', age: 42 })

console.log(user.name, user.age) // Property 'name' does not exist on type 'User'.

Upvotes: 3

Related Questions