awslabs / dynamodb-data-mapper-js

A schema-based data mapper for Amazon DynamoDB.
https://awslabs.github.io/dynamodb-data-mapper-js/
Apache License 2.0
817 stars 106 forks source link

Typescript 2.7+ defaults --strictPropertyInitialization to true causing errors #136

Open tpennetta opened 5 years ago

tpennetta commented 5 years ago

Since Typescript 2.7 there is a default setting which:

checks to ensure that each instance property of a class gets initialized in the constructor body, or by a property initializer.

Source: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html

So as an example, the following code will cause a compilation error as described below:

import { autoGeneratedHashKey, table } from '@aws/dynamodb-data-mapper-annotations';

@table('TestTable')
export default class TestClass {
    @autoGeneratedHashKey()
    ID: string;
}

Causes the following Error:

[ts] Property 'ID' has no initializer and is not definitely assigned in the constructor. [2564]

I am not sure what the proper solution is at the moment, but figured I would make the community aware.

Of course a solution right now is to disable this setting in tsconfig.json

"strictPropertyInitialization": false,  /* Enable strict checking of property initialization in classes. */
jeskew commented 5 years ago

I would recommend making every property optional. While this isn't required, as it makes interacting with mapped objects a bit more verbose, it accurately reflects how data can be queried from DynamoDB. Non-key fields are optional when writing records, and it's possible to construct a secondary index such that queries will not include fields that are used as keys on the table it indexes.

tpennetta commented 5 years ago

If it is considered best practice to have all fields optional, I believe perhaps this should be conveyed in the documentation as opposed to conveying to potential users of this library that we can construct classes as normal in Typescript, which in practice are limited to optional class members only.

Thank you for your reply 👍

jprivillaso commented 5 years ago

If I set the property to be required and initialize it inside the constructor, I receive the following error: Argument of type 'typeof TestClass' is not assignable to parameter of type 'ZeroArgumentsConstructor<any>'.

It is shown at the @table decorator before the class definition.

@table('TestTable')
export default class TestClass {
    @autoGeneratedHashKey()
    ID: string;

    constructor(ID: string) {
        this.ID = ID;
    }
}
karadza3a commented 5 years ago

If you still want to use a constructor, as a workaround for the error mentioned by @jprivillaso, you can redefine the ZeroArgumentsConstructor interface to disable the requirement:

// ./src/zero-arguments-constructor.override.ts

import { ZeroArgumentsConstructor } from '@aws/dynamodb-data-marshaller';

declare module '@aws/dynamodb-data-marshaller' {
  export interface ZeroArgumentsConstructor<T> {}
}

Note though that any database queries will not use the constructor, and fields marked as required will not be loaded if they are missing in the database. Add an explicit runtime check if you want to make sure every required field was loaded successfully.

krnbr commented 4 years ago

is there a workaround without doing the "strictPropertyInitialization": false setting

also without the overriding ZeroArgumentsConstructor