5

Consider the following class:

class Person {
  name: string = 'Shachar';
  age: number = 22;
  
  printPerson() {
    console.log(`name: ${this.name}, age: ${this.age}`);
  }
}

Is there a way to get an interface with the properties that would be "own" by an instance of this class? In this example, I want only the properties name and age, since printPerson will end up being part of the prototype of any instance, not own property.

Solutions that requires typing "name" and "age" explicitly are NOT acceptable since the class may have many properties and I would like to write them only once.

4
  • TS doesn't differentiate between own and inherited properties. Commented Aug 2, 2021 at 14:30
  • @VLAZ is there a good technical reason for that? Or will it be possible to implement it theoretically speaking? Commented Aug 2, 2021 at 15:07
  • The technical reason is that TS compares interfaces structurally. If an object matches an interface without explicitly being declared as that interface, it's still assignable to it. This aids compatibility with base JS code where interfaces don't exist. JS programming is often done by contract similar to how interfaces work but without having the interface to bind it more officially. A lot of duck-typing is used so as long as an object has a foo property, that might be good enough. With the dynamic nature of objects, it also doesn't make sense to restrict where and how foo comes about. Commented Aug 2, 2021 at 15:11
  • As for theoretical - you could create a mapped type from Person that excludes all properties that are functions. However, that is not only going to remove prototype methods but also instance properties with assigned functions to them. Commented Aug 2, 2021 at 15:13

1 Answer 1

4

Feels like there should be a better answer to this, and perhaps there is, but as a workaround, can you split your example class into two separate classes -- one which contains your properties and one which contains your methods? For example:

class PersonProperties {
    name: string = 'Shachar';
    age: number = 22;
}

class Person extends PersonProperties {
    printPerson() {
        console.log(`name: ${this.name}, age: ${this.age}`);
    }
}

You can then either utilize the implicit interface of PersonProperties or create a custom one as you see fit, e.g.

interface IPersonProperties extends PersonProperties {};

var x:IPersonProperties = {
    age: 500000,
    name: ""
}

Perhaaps not ideal, but it should work.

Sign up to request clarification or add additional context in comments.

Comments

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.