I want to register the @aws-sdk/client-ssm
with my my tsyring container like all the other aws services I am using. However when I am using "@aws-sdk/client-ssm": "3.435.0"
and register it like this:
import { container } from 'tsyringe';
import { SSMClient } from '@aws-sdk/client-ssm';
export const coreContainer = container.createChildContainer();
coreContainer.register(SSMClient, { useValue: new SSMClient({}) });
I get the following error:
TS2769: No overload matches this call.
The last overload gave the following error.
Argument of type typeof SSMClient is not assignable to parameter of type InjectionToken<SSMClient>
Type typeof SSMClient is not assignable to type constructor<SSMClient>
Types of construct signatures are incompatible.
Type
new (...[configuration]: [] | [SSMClientConfig]) => SSMClient
is not assignable to type new (...args: any[]) => SSMClient
Types of parameters __0 and args are incompatible.
Type any[] is not assignable to type [] | [SSMClientConfig]
Type any[] is not assignable to type [SSMClientConfig]
Target requires 1 element(s) but source may have fewer.
dependency-container.d.ts(30, 5): The last overload is declared here.
When I downgrade the @aws-sdk/client-ssm
to 3.301.0
it works without any issue.
So I was wondering what the difference is and if it is possible to use the newer version?
I spotted a difference in the constructors of the SSMClient
where the old version looks like this:
constructor(configuration: SSMClientConfig){
and the newer version looks like this:
constructor(...[configuration]: __CheckOptionalClientConfig<SSMClientConfig>) {
where this __CheckOptionalClientConfig
is a type from @smithy/types
But what exactly is the issue here? Can someone explain me this?
Adding to this question since I am currently blocked by this and spent the better part of a day trying to understand the underlying Typescript types and piecing it all together.
tl;dr I couldn't get it to work with regular tokens, so for my clients I went with
And it appears to resolve correctly when using the @injectable and @inject annotations on classes that require this client.
The difference between the old version and the updated version of the AWS client library is that wrapping of the
__CheckOptionalClientConfig
type in the constructor of the aws client class.For this description, I'll use the
CognitoIdentityProviderClient
instead ofSSMClient
since the class is in front of me but they should be functionally identical. For reference, these are the versions I'm on for both libraries from my package-lock.json file:These appear to be the latest versions of both libs at the time of writing. And like the OP, I'm trying to something similar:
Looking at the definition of the the
container.register
calls, they all look similar to this:register<T>(token: InjectionToken<T>, provider: FactoryProvider<T>): DependencyContainer;
And the thing that throws the typescript compiler error from the question is the fact that the definition of the aws client constructors don't match up with any of the definitions of InjectionToken.
InjectionToken is defined as this:
declare type InjectionToken<T = any> = constructor<T> | string | symbol | DelayedConstructor<T>;
The only possible values that the client classes can match here would be
constructor<T>
orDelayedConstructor<T>
as the token ofCognitoIdentityProviderClient
is not a string or symbol.Looking at
constructor<T>
, it's defined as:Fairly straightforward, it should match just about any class constructor since it's essentially saying the constructor can have any number of any type of parameters.
Here is the constructor of
CognitoIdentityProviderClient
:The left side of the
:
will mean it's expanding an array of configuration. The array of configuration is what is defined on the right side of the:
. So this leads back to what__CheckOptionalClientConfig
is.This is defined as:
Without unwrapping the
Exact
types, as it isn't super necessary, we see that it resolves to either[] | [T]
or[T]
, so either an empty array or an array containing the single elementT
.Applying the type we have to the generic and replacing it back down to simple typescript, we get the constructor to be:
And so the Typescript compiler complains because you want to fit a function with an either/or of 1 or 0 parameters to an interface with variable ones. Not entirely sure why it doesn't like this, but it doesn't.
I could not get it to work by passing in the regular class name without
.toString()
. I'm hoping that adding an answer here gives this question some traction, as I couldn't see anything about this on TSyringe github page at all, and to be honest the project seems to be a bit in maintenance mode.