Reputation: 1818
how can I export a type
by forcing it to be an instance.
I have tried many ways, I only found one solution, creating a static getter but I would like to remove my static getter.
Here context:
I would like to export a type of a instance of A from there $A.A
, for ref only.
export const $A = (() => {
class A {
static get default() {
return A.create();
}
static create() {
return new A();
}
constructor() {}
}
return { A };
})();
i try many way, here 7 of them ! no one work instead the way 1 ! but it because i add a static getter in the js class.
export type _1 = typeof $A.A.default;
export type _2 = typeof new $A.A;
export type _3 = typeof $A.A.create();
export type _4 = typeof $A.A();
export type _5 = typeof $A['A'];
export type _6 = $A.A;
export type _7 = typeof new ()=>$A.A;
// example somewhere in the project, i want tell A should be a instance and not a typeof!
function foo(A:_6)
So what the syntax to emulate a instance in a ts type for export somewhere for typage usage only. My project is in js, but using ts only for help the tsserver to understand my refs when he dont.
Upvotes: 1
Views: 419
Reputation: 329523
Preliminary note: the class A
code here lacks any instance structure (no properties or methods). All non-nullish values will be assignable to that instance type; see this FAQ entry for more info. Just to avoid this weirdness, I've added a property to the example class:
const $A = (() => {
class A {
static get default() {
return A.create();
}
static create() {
return new A();
}
constructor() { }
someStructure = 123; // add structure here
}
return { A };
})();
Now the compiler can tell that {someRandomThing: 123}
is not compatible with the A
type you're having trouble naming.
You might want to use the InstanceType<T>
utility type to pull out the return type of a construct signature:
type A = InstanceType<typeof $A.A>
You could write this yourself using conditional type inference:
type AlsoA = typeof $A.A extends new (...args: any) => infer I ? I : never;
Or, you could use the method we had to use before conditional types existed: TypeScript pretends that the prototype
property of a class is the same as its instance type. This isn't really true since the prototype generally only contains the methods and not other properties. But you can use it anyway:
type AlsoAlsoA = typeof $A.A.prototype;
Any of those should produce the same type.
Let's make sure it works:
function foo(a: A) { }
foo($A.A.create()) // okay
foo({ someRandomThing: 123 }) // error
// Argument of type '{ someRandomThing: number; }' is
// not assignable to parameter of type 'A'.
Looks good!
Upvotes: 2