6

Is it possible to get the name of a generic type param in typescript.

having this method.

getName<T>(): string {
   .... use some operator or something 
}

using it like this

class MyClass{
}


getName<MyClass>(); ///=> should return 'MyClass'

I've tried using https://www.npmjs.com/package/ts-nameof but it does not work.

Doing

const name = nameof<T>();

fails

Or maybe is there another way of achieving this ?

3 Answers3

3

You can't, not with typescript alone. Typescript only compile typescript to javascript. Javascript does not have something like generic type, so:

getName<MyClass>();

is compiled to

getName();

Of course, you do not expect to have different results of the same getName() without parameter. You need something to generate more code in order to do it, or add a parameter to your function:

function getName<T extends new (...args: any[]) => any>(clazz: T): string {
  return clazz.name;
}

class MyClass{
}

getName(MyClass);

It will only work with Class, which exists in runtime.

HTN
  • 3,388
  • 1
  • 8
  • 18
3

You need to ensure that you've correctly setup the prerequisites for using TypeScript transform plugins.

TypeScript transform plugins like ts-nameof require some setup because they rely on the transform compiler,ttypescript.

What you need to do:

1. Install ttypescript and ts-nameof:

npm i ttypescript ts-nameof @types/ts-nameof -D

2. Add ts-nameof to your plugins array in tsconfig.json:

{
  "compilerOptions": {
    "noEmitOnError": true,
    "target": "ES2020",
    "plugins": [{ "transform": "ts-nameof", "type": "raw" }],
  }
}

3. Change the path to your tsdk to the location ofttypescript in your vscode users settings:

"typescript.tsdk": "node_modules/ttypescript/lib" // this is for intellisense

4. Run with npx

npx ttsc

Then:

 const name = nameof<MyClass>();

will generate:

const name = "MyClass";

Example: ts-nameof-example

Original documentation:

ethane
  • 2,329
  • 3
  • 22
  • 33
  • I didnt know this existed. I think the cost of bringing two new libraries, change compiler, and etc, may be too much vs sending the type as an additional argument. Yet it is good to know this exist. – Kat Lim Ruiz Apr 20 '23 at 01:56
0

An approach is to define a class type interface for the parameter to the function:

export declare interface ClassType<T> {
    new (...args: any[]): T;
}
class MyClass {
}
function getName<TClass>(classType: ClassType<TClass>): string {
    return classType.name;
}

This results in you passing the name of the class as a parameter, which should provide the name:

let myName = getName(MyClass);

The downside is that you cannot do this to just a generic that is derived from the type of a data value.

Michael Erickson
  • 4,217
  • 2
  • 23
  • 10