In Typescript, declaring a class
magically creates both an interface and a value. But creating a class value through other means does not automatically make it a type, so e.g.
class Normal<T> {}
const Derived = Normal<number>
let normal: Normal<number> // <-- Fine and normal
let derived: Derived // <-- Derived is not a type
Somewhat amazingly, I discovered you can simply merge a type onto the value to manually mimic the class declaration, e.g.:
class Normal<T> {}
const Derived = Normal<number>
type Derived = Normal<number>
let normal: Normal<number> // <-- Fine and normal
let derived: Derived // <-- Now also fine
My question is this: If Derived
is created dynamically, is there a way to get this dual interface/value without manually adding steps, e.g.
class Normal<T> {}
function derive<T>(generic: T) {
const Derived = Normal<T>
type Derived = Normal<T> // obviously will not work
return Derived
}
const Derived = derive(number)
let normal: Normal<number>
let derived: Derived // <-- Derived is not a type
The context is I'm providing an API that creates many such classes and adds dynamic generics. I want to simplify the use of these classes for the API consumer.
The only way to get a class instance type to be declared without explicitly creating the type yourself is with a class
declaration (relevant doc). There was a feature request a while ago at microsoft/TypeScript#18942 so that any named value whose type is a class constructor would automatically also cause an instance type of the same name to exist, but this was declined.
Unless you're willing to write an actual class declaration such as
class Derived extends Normal<number> { }
then the only way to get a named type corresponding to your named value is to declare it separately as you discovered:
const Derived = Normal<number>
type Derived = Normal<number>
(Note that this is not considered declaration merging; named types and named values live in different spaces that do not conflict. Declaration merging is when you refer to the same named value multiple times or the same named type multiple times.)