Stripe + TypeScript: How to extend #types/stripe definitions for stripe-node? - node.js

I'm working on project, where we're using Stripe library for Node. We also want to use TypeScript on this project.
I've figured out that Stripe isn't providing official TypeScript definitions but I've found some community definitions #types/stripe on NPM. So I installed them and after a while I got an error:
Property 'sources' does not exist on type 'Stripe'.
Well there are missing some definitions, for example for this stripe.sources-related functionality.
I want to add missing definitions locally. So I need to extend this file:
#types/stripe/index.d.ts
I think that for the problem above I need:
to add property sources: Stripe.resources.Sources; to class Stripe,
to add class Sources to namespace resources,
to add missing function declarations to class Sources.
The problem is that I really don't know how. How should the .d.ts file with extensions look like? I've made many attempts according some examples and TypeScript docs but it always doesn't work. Do you have any idea?

I don't believe there's a way to augment the export-assigned Stripe class; the problem is similar to this open issue about augmenting a default-exported class. At this time, since you can't use augmentation, you'll have to fork the #types/stripe definitions for your project, and then you may as well make all the desired changes that way.

I think my colleague has found a solution that works for me. Here is how he made it:
import ST from 'stripe'
declare module 'stripe' {
namespace sources {
interface ISource extends IResourceObject {
...
}
interface ISourceCreationData {
...
}
}
namespace resources {
class Sources {
create(data: sources.ISourceCreationData): Promise<sources.ISource>;
retrieve(source: string, client_secret?: string): Promise<sources.ISource>;
}
}
class Stripe extends ST {
sources: ST.resources.Sources;
}
}

Related

Typescript imports destroys lookup?

I am trying to use a nodejs library like uuid in my typescript app. This simple import works just fine if I want to only use it in a specific class:
import { v4 } from "uuid";
class MyClass {
...
}
However, this makes the class MyClass not "discoverable" by any other files in my solution. Sure I could export it, but that forces me to import the class in every usage, and the problem spreads like a cancer to every file. Do I really have to import/export every single class/file in my application just because I want to produce a simple UUID?
I saw that I can use require instead, however typescript doesn't know what that keyword is. I found this question but neither installing #types/node nor the quick and dirty declare var require any works.
It really seems like I am jumping through a lot of unnecessary hoops just to generate a uuid in typescript. Am I doing something very wrong?
Thanks

How to find type definition file for xss-clean npm library

I just started to learn typescript and just started converting my nodejs/express application to typescript.
I have successfully got all types for the library using npm i #types/some-lib
only library, I can't find was npm i #types/xss-clean
where to find this library
import xss from 'xss-clean' //getting type definition error
app.use(xss())
If the library does not have many TypeScript users, chances are that no published types exist. In that case you can add your own to whatever degree of detail you wish.
You can create a type definition file, e.g. xss-clean.d.ts:
declare module 'xss-clean'
{
const value: Function;
export default value;
}
[More on declaration files]
You can use this page to look up if a package has types or not. xss-clean does not seem to have any types yet, so you would have to declare them by yourself.
More info on that here.

What is the best way to organize the code of a nodejs-express project, using TypeScript?

While trying to organize the code of my first NodeJS-express project, I ran into some doubts about the use of namespaces, modules and classes. When to choose one? When another?
For example, my project is structured (simplifying) in.
routers -> controllers -> services -> repositories.
The possibilities I thought of to manage these "entities" are the following:
Classes
Classes with static methods
Singletons
Simple module export
Namespaces
Classes
I thought of avoiding them right away, since the above-mentioned entities do not need to memorize any state. Furthermore, they would complicate the code due to the need to be instantiated.
Classes with static methods
They are correct? Or rather a simple namespace or simple export of the modules?
Class + Singletons
A way of organizing the code in a "nicer" way than the simple class, but which does not convince me, since reading on the net that the singleton in TypeScript is replaceable with the namespace.
Simple module export
The way I thought to implement immediately, for example in this way (file user.repository.ts):
const add = async (user: User): Promise<void> => {
if(await canBeAdded(user)) {
//save user;
} else {
// throw error
}
}
export const UserRepository = {
add
}
It's corrects? Or am I not properly using what TypeScript offers? Being the first time I use this language, I would like to be sure I chose the right path.
Namespaces
Are they a better choice to develop the code published above? Are you advised against?
Thank you in advance for the answers! Any advice is welcome!
P.S. I know that, once the TypeScript is compiled, in Javascript the classes are practically syntactic sugar. What I'm interested in knowing are the best practices for writing good code in TypeScript.

module augmentation on node module that exports class: how to add instance property?

Update: I found exactly the same question on Reddit. Still looking for an answer though, since on Reddit, only a hack in node_modules/#types/ws/index.d.ts is proposed, which I rather not touch for obvious reasons.
I'm using the ws node module to create a socket server. Its typings are of the following structure:
declare class WebSocket extends events.EventEmitter {
// ...
}
declare namespace WebSocket {
// ...
}
export = WebSocket;
What is the correct way of extending the typings so that I can add an instance property id to a WebSocket class? I tried the following in a regular typescript(.ts) file:
class WebSocketServerWithId extends WebSocket {
id: number;
}
Which returns [ts] Type 'typeof WebSocket' is not a constructor function type. [2507]. I've also tried to use the approach in this Stackoverflow question with the same error as a result. I've read the documentation on declaration merging but still am confused.
Anyone knows hows to add an instance property to a class defined and exported in an external node module? (written in commonjs, meant to be executed in node alone).

Puppet configuration for multiple classes in a module

I'd like to use and configure the puppet-nginx module, although this is a general question about Puppet configuration.
Exec { path => [ "/bin/", "/sbin/" , "/usr/bin/", "/usr/sbin/" ] }
class nginx-setup {
class { 'nginx': }
}
include nginx-setup
Works great! Now, if I follow the docs for configuration I end up with something like this:
Exec { path => [ "/bin/", "/sbin/" , "/usr/bin/", "/usr/sbin/" ] }
class nginx-setup {
class { 'nginx': }
class { 'nginx::package':
package_source => 'nginx-mainline'
}
}
include nginx-setup
Error: Duplicate declaration: Class[Nginx::Package] is already declared
I tried include nginx instead of my first class declaration, but I think the module's init.pp is declaring the nginx::package class already and I still get duplicate declaration error. Even if that worked, what if I wanted to apply more configurations to another class within the nginx module? For example:
Exec { path => [ "/bin/", "/sbin/" , "/usr/bin/", "/usr/sbin/" ] }
class nginx-setup {
class { 'nginx': }
class { 'nginx::package':
package_source => 'nginx-mainline'
}
class { 'nginx::config':
nginx_error_log => 'syslog:server=localhost',
}
}
include nginx-setup
Many duplicate definitions!
So it feels like I should be passing everything required into my initial class declaration, but I can't seem to find the right way to do it. What is the best way to achieve this?
TL;DR
Consider using Hiera after all, for this module is tricky to use otherwise, due to some shortcomings in Puppet's handling of class parameters.
Long answer:
That's a loaded question, actually, even though it should not be. You correcly inferred the gist already. But let's take it step-by-step.
Module structure
It is now considered best practice (citation needed, although Ryan Coleman from Puppet Labs mentioned this in a recent presentation at FOSDEM) to expose all tunables of a module in its central class (here, class nginx).
This way, it is clear for the user that they need to look up the appropriate parameter for this one class, instead of going on a hunt for the appropriate class to tune.
The nginx module you picked seems to adopt this in large parts, but not consequently.
Hacks using defined()
As you have noticed, the module author added some shortcuts to allow you to declare your classes "safely" if you make sure the nginx::config class is encountered before the nginx class proper, lexically.
This is dangerous, because in a complex manifest, this might not be easy to assert.
include vs. class { }
Class parameters are problematic, because they lead to include being less safe than it used to be, because they don't mix well with class { 'name': ... } style declarations. The latter are always bad news because they have to be unique, as you are now experiencing.
It is best to stick to include as much as possible, which leads to the next issue.
Hiera
With parameterized classes, you really want to adopt Hiera as soon as possible. Defining class parameters as data is almost universally superior to doing it in the manifest. I understand the desire to stick to simple constructs first, but due to the issue described above, it can really make life harder on yourself.
It turns out it was module-specific. jfryman/puppet-nginx module classes are loaded automatically except for nginx::config (unless it isn't declared already) and most other classes inherit their settings from nginx::config. The correct solution for this module is;
class nginx-setup {
class { '::nginx::config':
http_access_log => 'syslog:server=localhost,tag=nginx,severity=info',
nginx_error_log => 'syslog:server=localhost,tag=nginx,severity=info',
}
class { '::nginx':
package_source => 'nginx-mainline',
}
}
include nginx-setup
jfryman/puppet-nginx is moving towards Hiera configurations and this might not work for long. I wanted a pure Puppet solution (to learn) before integrating Hiera but I wouldn't recommend it for everyone...

Resources