4

I have two unrelated classes and a function that interacts with the constructor.name I don't want to use the any type. Is there a way I can write the following in a typescript way? I want someClass to represent any class but I'm not exactly sure how to write that.

class MyClass {
    //
}

class MyOtherClass {
    // 
}

const getClassName = (someClass, name = someClass.constructor.name) => {
    console.log(someClass)
    console.log(someClass.constructor.name)
}

getClassName(MyClass)
2
  • Likely new (...args: any[]) => any Commented Oct 17, 2022 at 15:46
  • You can find some OOP typings in my article Commented Oct 24, 2022 at 10:02

2 Answers 2

4
+25

You can define the type for a class constructor, like this:

type ClassConstructor<T> = {
  new (...args: any[]): T;
};

const getClassName = (someClass: ClassConstructor<any>) => {
    console.log(someClass.name)
}

getClassName(MyClass)
getClassName(MyOtherClass)
// this is a complie error: not a constructor
getClassName(() => 1)
// this is a complie error: instance - not a class
getClassName(new MyClass())

Playground Example

But beware, that the class-name may be different in production: i.e. when you use webpack to minify/uglify your code

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

1 Comment

It worth using inference on function arguments. See here
0

From the lib.es5.d.ts (the file with Record / Partial / etc definitions) you can see builtin definition of

/**
 * Obtain the return type of a constructor function type
 */
type InstanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...args: any) => infer R ? R : any;

So, the constructor is defined as

type Constructor<T> = abstract new (...args: any) => T;

And your function is

const getClassName = (someClass: Constructor<any>, name = someClass.constructor.name) => {
    console.log(someClass)
    console.log(someClass.constructor.name)
}

or

const getClassName = (someClass: abstract new (...args: any) => any, name = someClass.constructor.name) => {
    console.log(someClass)
    console.log(someClass.constructor.name)
}

If you want to use the class name and keep your class itself on type level, you can use Branded (oko Opaque) types:

type Constructor<T> = abstract new (...args: any) => T;
// I tend to name non-object subtipes camelCase
type className<T> = string & {__classNameOf: T}
// or
declare const classNameOfSymbol: unique symbol
type className2<T> = string & {[classNameOfSymbol]: T}

function getClassName<T> (someClass: Constructor<T>, name = someClass.constructor.name): className<T> {
  return name as className<T>
}

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.