sam-goodwin / typesafe-dynamodb

TypeSafe type definitions for the AWS DynamoDB API
Apache License 2.0
207 stars 11 forks source link

Type Error #49

Closed 1oglop1 closed 1 year ago

1oglop1 commented 1 year ago

Hi I get the type error with the following code

"devDependencies": {
    "aws-sdk-client-mock": "^2.1.1",
    "typesafe-dynamodb": "^0.2.3"
  },
  "dependencies": {
    "@aws-sdk/client-dynamodb": "^3.369.0",
    "@aws-sdk/client-rds": "^3.303.0",
    "@aws-sdk/lib-dynamodb": "^3.369.0",
    "@bluecodecom/lambda-lib": "*",
    "@hexlabs/dynamo-ts": "^4.0.148",
    }

import { TypeSafeDocumentClientV3 } from "typesafe-dynamodb/lib/document-client-v3";
import { TypeSafePutDocumentCommand } from "typesafe-dynamodb/lib/put-document-command";
import { DynamoDB } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocument } from "@aws-sdk/lib-dynamodb";

const dynamoClient = new DynamoDB({
      endpoint: {hostname: "localhost", port: 5001, protocol: "http:", path: "/"},
      region: "local-env",
      credentials: {accessKeyId: "x", secretAccessKey: "x"},
    });

    const documentClient = DynamoDBDocument.from(dynamoClient) as TypeSafeDocumentClientV3<PaymentNotificationDB, "pk", "sk">;;
    interface PaymentNotificationDB {
      pk: string;
      sk: string;
    }

    const putPaymentNotification = TypeSafePutDocumentCommand<PaymentNotificationDB>();

    const d = new Date()
    const id = `${d.getHours()}-${d.getMinutes()}-${d.getSeconds()}`

    const cmd = new putPaymentNotification({
      TableName: "table",
      Item: {
        sk: `p1-${id}`,
        pk: `s2-${id}`,
      },
    });

const result = await documentClient.send(cmd); // here is the type error
click to expand Error Log ``` TSError: ⨯ Unable to compile TypeScript: src/post.spec.ts(134,46): error TS2345: Argument of type 'Command, PutItemOutput & MetadataBearer, DynamoDBClientResolvedConfig, any, any> & { ...; }' is not assignable to parameter of type 'Command, ServiceOutputTypes, ServiceOutputTypes, SmithyResolvedConfiguration<...>>'. The types of 'middlewareStack.concat' are incompatible between these types. Type ', OutputType extends PutItemOutput & MetadataBearer>(from: MiddlewareStack<...>) => MiddlewareStack<...>' is not assignable to type ', OutputType extends ServiceOutputTypes>(from: MiddlewareStack) => MiddlewareStack<...>'. Types of parameters 'from' and 'from' are incompatible. Type 'MiddlewareStack' is not assignable to type 'MiddlewareStack & MetadataBearer>'. Types of property 'add' are incompatible. Type '{ (middleware: InitializeMiddleware, options?: (InitializeHandlerOptions & AbsoluteLocation) | undefined): void; (middleware: SerializeMiddleware<...>, options: SerializeHandlerOptions & AbsoluteLocation): void; (middleware: BuildMiddleware<...>, options: BuildHandlerOptions & AbsoluteLocation...' is not assignable to type '{ (middleware: InitializeMiddleware & MetadataBearer>, options?: (InitializeHandlerOptions & AbsoluteLocation) | undefined): void; (middleware: SerializeMiddleware<...>, options: SerializeHandlerOptions & AbsoluteLocation): void; (middlewar...'. Types of parameters 'middleware' and 'middleware' are incompatible. Types of parameters 'next' and 'next' are incompatible. Type 'InitializeHandler' is not assignable to type 'InitializeHandler & MetadataBearer>'. Type 'Promise>' is not assignable to type 'Promise & MetadataBearer>>'. Type 'InitializeHandlerOutput' is not assignable to type 'InitializeHandlerOutput & MetadataBearer>'. Types of property 'output' are incompatible. Type 'OutputType' is not assignable to type 'PutItemOutput & MetadataBearer'. Type 'ServiceOutputTypes' is not assignable to type 'PutItemOutput & MetadataBearer'. Type 'BatchExecuteStatementCommandOutput' is not assignable to type 'PutItemOutput & MetadataBearer'. Types of property 'ConsumedCapacity' are incompatible. Type 'ConsumedCapacity[] | undefined' is not assignable to type 'ConsumedCapacity | undefined'. Type 'OutputType' is not assignable to type 'PutItemOutput'. Type 'ServiceOutputTypes' is not assignable to type 'PutItemOutput'. Type 'BatchExecuteStatementCommandOutput' is not assignable to type 'PutItemOutput'. Types of property 'ConsumedCapacity' are incompatible. Type 'ConsumedCapacity[] | undefined' is not assignable to type 'ConsumedCapacity | undefined'. Type 'ConsumedCapacity[]' has no properties in common with type 'ConsumedCapacity'. at createTSError (node-path/node_modules/ts-node/src/index.ts:261:12) at getOutput (node-path/node_modules/ts-node/src/index.ts:367:40) at Object.compile (node-path/node_modules/ts-node/src/index.ts:558:11) at Module.m._compile (node-path/node_modules/ts-node/src/index.ts:439:43) at Module._extensions..js (node:internal/modules/cjs/loader:1159:10) at Object.require.extensions. [as .ts] (node-path/node_modules/ts-node/src/index.ts:442:12) at Module.load (node:internal/modules/cjs/loader:981:32) at Function.Module._load (node:internal/modules/cjs/loader:827:12) at Module.require (node:internal/modules/cjs/loader:1005:19) at require (node:internal/modules/cjs/helpers:102:18) at Object.exports.requireOrImport (node-path/node_modules/mocha/lib/nodejs/esm-utils.js:53:16) at Object.exports.loadFilesAsync (node-path/node_modules/mocha/lib/nodejs/esm-utils.js:100:20) at singleRun (node-path/node_modules/mocha/lib/cli/run-helpers.js:125:3) at Object.exports.handler (node-path/node_modules/mocha/lib/cli/run.js:370:5) ```
sam-goodwin commented 1 year ago

Looking into it. Curious, what TS version are you using ?

1oglop1 commented 1 year ago

4.9.5, I could try with a different version

1oglop1 commented 1 year ago

Interesting, I upgraded to 5.1.6 and the type error is gone 🎉 !

I have a bit OT question. I have a table with the GSI attribute sent which I'd like to be a boolean however when defining the table I can only use S then my type looks like this

interface PaymentNotificationDB {
      pk: string;
      sk: string;
      sent: boolean;
    }

which works with const putPaymentNotification = TypeSafePutDocumentCommand<PaymentNotificationDB>(); but then

const putCmd = new putPaymentNotification({
      TableName,
      Item: s,
    });

const putResult = await documentClient.send(putCmd);

returns ValidationException: Invalid attribute value type. Am I missing something or do the attributes which are indexes must be a string?

Table definition ``` await dynamoClient.createTable({ TableName, ProvisionedThroughput: { WriteCapacityUnits: 1, ReadCapacityUnits: 1, }, AttributeDefinitions: [ { AttributeName: "pk", AttributeType: "S", }, { AttributeName: "sk", AttributeType: "S", }, { AttributeName: "sent", AttributeType: "S", }, ], KeySchema: [ { KeyType: "HASH", AttributeName: "pk", }, { KeyType: "RANGE", AttributeName: "sk", }, ], GlobalSecondaryIndexes: [ { IndexName: "SentIndex", Projection: { ProjectionType: "ALL", }, KeySchema: [ { AttributeName: "sent", KeyType: "HASH", }, ], ProvisionedThroughput: { WriteCapacityUnits: 1, ReadCapacityUnits: 1, }, }, ], }); }); ```
sam-goodwin commented 1 year ago

Interesting, I upgraded to 5.1.6 and the type error is gone 🎉 !

Yay!

returns ValidationException: Invalid attribute value type. Am I missing something or do the attributes which are indexes must be a string?

It looks like the table definition defines sent as a S.

AttributeDefinitions: [
    { AttributeName: "pk", AttributeType: "S" },
    { AttributeName: "sk", AttributeType: "S" },
    { AttributeName: "sent", AttributeType: "S" },
  ],

I assume you're doing this because PK/SK only supports S/B/N. The reason for your failure is that you are trying to store a JS boolean in a S field. The SDK will convert that boolean into a { BOOL: true|false} which does not comply with your defined schema.

It is not possible to use a BOOL field as a PK/SK in a GSI. You will have to convert this to a string for it to work.

typesafe-dynamodb has no runtime component (it is types only) so if you're getting a runtime error then it is the service + SDK that is causing the problem

1oglop1 commented 1 year ago

Thanks for the help. I think that we can close this as no issue. Unless you have time to test the problem with the version of TS I mentioned earlier.