I'm new to typescript to bear with me here if this is not how things are supposed to work.
I have a couple of goals in converting this js to ts.
Item = {}
Item.buy = function (id) {}
Item.sell = function (id) {}
I'm trying to get intellisense to autocomplete on Item.
either buy or sell. I would also want to use dot notation to create these methods in arbitrary files without putting everything in the initial bracket. So I have something like this:
interface Item {}
const Item: Item = {};
interface Item {
buy?: Function
}
Item.buy = function () {
Item.render()
return "bought"
}
interface Item {
sell?: Function
}
Item.sell = function () {
Item.render()
return "sold"
}
interface Item {
render?: Function
}
Item.render = function () {
return 1
}
The problem here now is that render is an optional property and hence I get this error:
Cannot invoke an object which is possibly 'undefined'.
How can I make ts not check for this error? Since Item is not a class there's only ever going to be 1 item and it'll definitely have the render method, there is not ever going to be an instance where that error checking is useful. Or to put it another way, it's not actually optional, I only set it to be optional to work around const Item: Item = {};
erroring if I don't have it be optional.
Is there a way to let ts know that or use a different pattern in the first place?
CodePudding user response:
SOLUTION 1:
Since you have not defined any method inside Item
interface Item {}
So you can check whether render
method exist or not on Item
as:
Item.buy = function () {
if(Item.render) Item.render(); // CHANGE
return "bought";
}
SOLUTION 2:
Best solution would be to add type of render
on interface
Item
as:
interface Item {
render: () => void;
}
and then you can use it as:
Item.buy = function () {
Item.render();
return "bought";
}
CodePudding user response:
My inclination here would be to use namespace
s instead of an interface to hold these functions. It could look like this:
namespace Item {
export const buy = function () {
Item.render()
return "bought"
}
}
namespace Item {
export const sell = function () {
Item.render()
return "sold"
}
}
namespace Item {
export const render = function () {
return 1
}
}
Then you'd be able to access them the same way, as methods on the singleton Item
value:
// elsewhere
console.log(Item.sell()); // "sold"
Note that namespace
is a TypeScript specific feature, and nowadays new code is generally encouraged to use module
s instead where possible. I don't really know if there's a good way to get this sort of behavior with modules, because the part we're using, merging different things into a common JS value, is not really how modules works. Maybe declaration merging and importing would give this to you, but I don't know.
Anyway, as long as you're okay with a TS-specific feature, then namespace
would be an idiomatic way to represent this sort of gradual building of a singleton.