aws-amplify / amplify-category-api

The AWS Amplify CLI is a toolchain for simplifying serverless web and mobile development. This plugin provides functionality for the API category, allowing for the creation and management of GraphQL and REST based backends for your amplify project.
https://docs.amplify.aws/
Apache License 2.0
87 stars 75 forks source link

TypeScript Type Inference Error with AWS Amplify Data Schema in Monorepo Environment #2564

Open rnrnstar2 opened 3 months ago

rnrnstar2 commented 3 months ago

Environment information

System:
  OS: macOS 14.0
  CPU: (10) arm64 Apple M2 Pro
  Memory: 202.08 MB / 16.00 GB
  Shell: /bin/zsh
Binaries:
  Node: 20.5.0 - /usr/local/bin/node
  Yarn: 1.22.19 - /usr/local/bin/yarn
  npm: 9.8.0 - /usr/local/bin/npm
  pnpm: 8.15.5 - ~/Library/pnpm/pnpm
NPM Packages:
  @aws-amplify/backend: 1.0.2
  @aws-amplify/backend-cli: 1.0.3
  aws-amplify: 6.3.2
  aws-cdk: 2.142.0
  aws-cdk-lib: 2.142.0
  typescript: 5.4.5
AWS environment variables:
  AWS_DEFAULT_PROFILE = cloudteam
  AWS_STS_REGIONAL_ENDPOINTS = regional
  AWS_NODEJS_CONNECTION_REUSE_ENABLED = 1
  AWS_SDK_LOAD_CONFIG = 1

Description

I'm encountering a TypeScript type inference error when using AWS Amplify's data schema in a monorepo environment. The node_modules directory is present only at the root level of the monorepo.

.
├── README.md
├── apps
│   └── admin
│       ├── README.md
│       ├── amplify.yml
│       ├── app
│       ├── next-env.d.ts
│       ├── next.config.js
│       ├── package.json
│       ├── postcss.config.js
│       ├── public
│       ├── tailwind.config.ts
│       └── tsconfig.json
├── package-lock.json
├── package.json
├── packages
│   ├── eslint-config
│   │   ├── README.md
│   │   ├── library.js
│   │   ├── next.js
│   │   ├── package.json
│   │   └── react-internal.js
│   ├── shared-backend
│   │   ├── amplify
│   │   ├── amplify.yml
│   │   ├── amplify_outputs.json
│   │   ├── hooks
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── provider
│   │   ├── tsconfig.json
│   │   └── tsconfig.lint.json
│   ├── tailwind-config
│   │   ├── package.json
│   │   ├── tailwind.config.ts
│   │   └── tsconfig.json
│   ├── typescript-config
│   │   ├── base.json
│   │   ├── nextjs.json
│   │   ├── package.json
│   │   └── react-library.json
│   └── ui
│       ├── components
│       ├── dist
│       ├── package.json
│       ├── postcss.config.js
│       ├── styles.css
│       ├── tailwind.config.ts
│       ├── tsconfig.json
│       └── tsconfig.lint.json
├── test.json
├── tsconfig.json
└── turbo.json
import { generateClient } from "aws-amplify/data";
import { type Schema } from "../amplify/data/resource";
type Team = Schema["Team"];

const client = generateClient<Schema>();

await client.models.Team.create({
  id: "testid",
  name: "test",
});
(property) name: string
Type 'string' is not assignable to type '{ [x: number]: string; toString: () => string; charAt: (pos: number) => string; charCodeAt: (index: number) => number; concat: (...args: (string | ConcatArray<string>)[]) => string[]; ... 71 more ...; id?: string; }'.ts(2322)
util.d.ts(15, 130): The expected type comes from property 'name' which is declared here on type '{ [x: string]: { [x: number]: string; toString: () => string; charAt: (pos: number) => string; charCodeAt: (index: number) => number; concat: (...args: (string | ConcatArray<string>)[]) => string[]; ... 71 more ...; readonly [Symbol.unscopables]: { ...; }; }; [x: number]: { ...; }; id?: string; }'

Steps to Reproduce:

  1. Set up a monorepo environment with a single node_modules directory at the root.
  2. Use AWS Amplify Data Schema to create a model.
  3. Attempt to create a model instance with a type that includes a string property.

Expected Behavior: The type inference should correctly recognize the string type for the name property without any errors.

Current Behavior: TypeScript throws an error, indicating that the string type is not assignable to the expected type, which includes various methods and properties.

Environment: Turborepo

スクリーンショット 2024-05-17 1 38 31

スクリーンショット 2024-05-17 1 38 59

chrisbonifacio commented 3 months ago

Hi @rnrnstar2, this seems similar to an issue we are currently aware of and working on a fix for. Can you share your schema to reproduce locally so we can confirm?

rnrnstar2 commented 3 months ago
import { type ClientSchema, a, defineData } from "@aws-amplify/backend";
import { oripaPostConfirmation } from "../functions/OripaPostConfirmation/resource";

const schema = a
  .schema({
    Team: a
      .model({
        name: a.string().required(),
        s3ImgKey: a.string(),
        shops: a.hasMany("Shop", "teamId"),
        teamMembers: a.hasMany("TeamMembers", "teamId"),
      })
      .authorization(allow => [allow.owner().to(['create', 'read', 'update']), allow.authenticated().to(["read", "update"])]),
    Shop: a
      .model({
        name: a.string().required(),
        s3ImgKey: a.string(),
        teamId: a.id(),
        team: a.belongsTo("Team", "teamId"),
        shopMembers: a.hasMany("ShopMembers", "shopId"),
      })
      .authorization(allow => [allow.owner().to(['create', 'read', 'update']), allow.authenticated().to(["read", "update"])]),
    Member: a
      .model({
        name: a.string().required(),
        s3ImgKey: a.string(),
        email: a.email().required(),
        teamMembers: a.hasMany("TeamMembers", "memberId"),
        shopMembers: a.hasMany("ShopMembers", "memberId"),
      })
      .secondaryIndexes((index) => [
        index("email").sortKeys(["name"]).queryField("listByEmail"),
      ])
      .authorization(allow => [allow.owner().to(['create', 'read', 'update']), allow.authenticated().to(["read"])]),
    TeamMembersType: a.enum(["OWNER", "MEMBER"]),
    TeamMembers: a
      .model({
        type: a.ref("TeamMembersType").required(),
        teamId: a.id().required(),
        memberId: a.id().required(),
        team: a.belongsTo("Team", "teamId"),
        member: a.belongsTo("Member", "memberId"),
      })
      .authorization(allow => [allow.owner().to(['create', 'read', 'update']), allow.authenticated().to(["read", "update", "create"])]),
    ShopMembersType: a.enum(["OWNER", "MEMBER"]),
    ShopMembers: a
      .model({
        type: a.ref("ShopMembersType").required(),
        shopId: a.id().required(),
        memberId: a.id().required(),
        shop: a.belongsTo("Shop", "shopId"),
        member: a.belongsTo("Member", "memberId"),
      })
      .authorization(allow => [allow.owner().to(['create', 'read', 'update']), allow.authenticated().to(["read", "update", "create"])]),
    OnePieceType: a.enum(["CHARACTER", "EVENT", "STAGE", "LEADER"]),
    OnePieceColor: a.enum([
      "RED",
      "BLUE",
      "GREEN",
      "YELLOW",
      "PURPLE",
      "BLACK",
    ]),
    OnePieceAttribute: a.enum([
      "STRIKE",
      "SLASH",
      "WISDOM",
      "RANGED",
      "SPECIAL",
    ]),
    OnePieceRarity: a.enum(["C", "UC", "R", "SR", "SEC", "P", "L", "SP"]),
    OnePieceItem: a
      .model({
        name: a.string().required(),
        s3ImgKey: a.string().required(),
        type: a.ref("OnePieceType").required(),
        colors: a.ref("OnePieceColor").array().required(),
        features: a.string().array().required(),
        attributes: a.ref("OnePieceAttribute").array(),
        rarity: a.ref("OnePieceRarity").required(),
        cost: a.integer(),
        power: a.integer(),
        counter: a.integer(),
        text: a.string(),
        getInfo: a.string(),
        colorKey: a.string(), // ソートキー用
        featureKey: a.string(), // ソートキー用
        attributeKey: a.string(), // ソートキー用
      })
      .secondaryIndexes((index) => [
        index("getInfo").sortKeys(["colorKey", "type"]).queryField("listByGetInfo"),
      ])
      .authorization(allow => [allow.owner().to(['create', 'read', 'update']), allow.authenticated().to(["read", "update", "create"])]),
  })
  .authorization(allow => [allow.resource(oripaPostConfirmation)]);

export type Schema = ClientSchema<typeof schema>;

export const data = defineData({
  schema,
  name: "OripaData",
  authorizationModes: {
    defaultAuthorizationMode: "userPool",
  },
});

this is data resource.ts.

chrisbonifacio commented 2 months ago

@rnrnstar2 can you check your tsconfig and confirm that you have strict mode enabled? If it's enabled and you are still experiencing this issue, please let us know.

waynet-ihm commented 1 month ago

created a repo with this issue - still a blocker for me

https://github.com/waynet-ihm/amplify-issue

chrisbonifacio commented 1 month ago

@waynet-ihm thank you! I was able to reproduce your error right away.

CleanShot 2024-07-11 at 14 49 42@2x

Although now I realize it's different from the one originally described here. Perhaps this deserves its own issue. If you create a new issue, I'll mark it a bug for the team to investigate further.

chrisbonifacio commented 1 month ago

Hi @rnrnstar2 , just wanted to share an update on this: the team is aware of and working on a fix for these reference/type annotation errors