1

I am trying to detect a specific Class type using TypeScript. Seems like it should be a straight forward task but I haven't found any straight forward documentation on how to do this. Here is a simple use case example:

Class Car {}

Class Ford extends Car {}

Class Audi extends Car {}

let mustang = new Ford();
let a6 = new Audi();

// With an instance of Ford and Audi, how can I generically detect the type??
console.log(a6.getType()); // <--- this would return Audi
console.log(mustang.getType()); // <--- this would return Ford

I am trying to understand if there is any easy way to detect the most specific version of Car (in this case Audi or Ford). I understand that "getType()" is not a real function, but was interested to know if there is any easy way to achieve this, or a different way of thinking about this

jbambrough
  • 597
  • 2
  • 7
  • 15
  • [You *can* do that by checking the prototype](https://stackoverflow.com/questions/1249531/how-to-get-a-javascript-objects-class). However, you very likely shouldn't be doing that as you shouldn't really rely on the name of a class has. The majority of times this leads to brittle code. – VLAZ Feb 16 '21 at 20:42
  • Ya, I was trying to avoid that using old school JS code. Seems like TS would support something more elegant. What would you recommend? – jbambrough Feb 16 '21 at 20:45
  • 2
    TypeScript *only* exists at compile time. Afterwards it's converted to JavaScript. So if you want to find a class name *at runtime* (and that's when logging happens), you need to use JavaScript. What I would suggest depends on what you're actually trying to do, as "find the class name" is usually [an XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). If you want to use that information to do something, then there is likely an alternative. If you just want to know how to get the name as curiosity, then...it's just a JS question. – VLAZ Feb 16 '21 at 20:48

2 Answers2

1

Typescript does not provide access to the types at runtime. So you need the good old JS way, class.constructor.name does what you need.

I.e.

class Car {}

class Ford extends Car {}

class Audi extends Car {}

let mustang = new Ford();
let a6 = new Audi();

console.log(mustang.constructor.name)
console.log(a6.constructor.name)

Update using JulienD's answer..
If there is a chance the name and the class name can be different then you may want it to improve a bit. It is also handy to have a getter for it rather than referencing this.constructor.name E.g.

    class Car {
       carType: string = '';
       public get name(): string {
          return this.carType || this.constructor.name;
       }
    }

    class Ford extends Car {
        carType: string = 'Shelby';
    }

    class Audi extends Car {}

    let mustang = new Ford();
    let a6 = new Audi();

    console.log(mustang.name)
    console.log(a6.name)
Zoltan Magyar
  • 874
  • 1
  • 6
  • 19
  • I like this. Is this standard/best practice? Are there any "gotchas" I should be aware of here? – jbambrough Feb 16 '21 at 20:49
  • 1
    TBH I'm not a big fan of referencing class names in the code. That suggests a bad code design to me. E.g. just consider the case when you will need to add a new car name like "BMW M" or "Lynk & Co" or any other name what you can not use as a TS class name. Personally I would only use ```this.constructor.name``` only for debugging purposes (e.g. include in the logs in case of errors to help finding the failing code). Due to the above reasons I prefer JulienD's solution. I have improved that a bit and updated my answer. – Zoltan Magyar Feb 17 '21 at 08:48
1

If you can modify the classes, you can add a property that is overridden in subclasses, for example

class Car {
  name: string = 'car';
}

class Ford extends Car {
  name = 'Ford';
}

class Audi extends Car {
  name = 'Audi';
}

let mustang = new Ford();
let a6 = new Audi();

console.log(a6.name); // <--- returns Audi
console.log(mustang.name); // <--- returns Ford

JulienD
  • 7,102
  • 9
  • 50
  • 84