There are two class:
class STRING_TYPE {
name():string{
return "one";
}
}
class NUMBER_TYPE {
name():number{
return 1;
}
}
I want to write a generic function:
- create an object of the given class
- call name() method, and return its value; In javascript, code like:
function foo(classType) {
const obj = new classType();
return obj.name();
}
How to write it in typescript?
// it doesn't work.
function foo<T>(typ: T): ReturnType<T.name>{
const obj = new T();
return obj.name();
}
CodePudding user response:
You need to put a constraint for classType
argument:
class STRING_TYPE {
value(): string {
return "one";
}
}
class NUMBER_TYPE {
name(): number {
return 1;
}
}
type AnyClass<Return> = new (...args: any[]) => Return
const foo = <Klass extends AnyClass<{ name: () => number }>>(classType: Klass) =>
new classType().name();
const result = foo(NUMBER_TYPE)
foo
expects a class constructor with name
method. TS is able to infer return type.
UPDATE
class STRING_TYPE {
name(): string {
return "one";
}
}
class NUMBER_TYPE {
name(): number {
return 1;
}
}
type AnyClass<R> = new (...args: any[]) => R
const foo = <
Return extends { name: () => any },
Klass extends AnyClass<Return>,
>(classType: Klass): ReturnType<InstanceType<Klass>['name']> =>
new classType().name()
foo(NUMBER_TYPE) // number
foo(STRING_TYPE) // string
CodePudding user response:
You can do something like this:
class STRING_TYPE {
value(): string {
return 'one';
}
}
class NUMBER_TYPE {
name(): number {
return 1;
}
}
function foo(classType: typeof STRING_TYPE): string; // ReturnType<STRING_TYPE['value']>
function foo(classType: typeof NUMBER_TYPE): number; // ReturnType<NUMBER_TYPE['name']>
function foo(classType: typeof STRING_TYPE | typeof NUMBER_TYPE) {
const obj = new classType();
return obj instanceof STRING_TYPE ? obj.value() : obj.name();
}
const bar = foo(STRING_TYPE);
const baz = foo(NUMBER_TYPE);
console.log(bar, baz);
Assuming you did a typo while asking question here, and both your classes have a name
method, you can do this:
class STRING_TYPE {
name(): string {
return 'one';
}
}
class NUMBER_TYPE {
name(): number {
return 1;
}
}
type ClassType =
| typeof STRING_TYPE
| typeof NUMBER_TYPE;
function foo<T extends ClassType>(classType: T) {
const obj = new classType();
return obj.name() as ReturnType<InstanceType<T>['name']>;
}
const bar = foo(STRING_TYPE);
const baz = foo(NUMBER_TYPE);
console.log(bar, baz);
References: