ScaleLeap / amazon-mws-api-sdk

A fully typed TypeScript and Node.js Amazon MWS API Unofficial SDK
https://npm.im/@scaleleap/amazon-mws-api-sdk
MIT License
20 stars 12 forks source link

How do I go about implementing circular interfaces with purify-ts? #50

Closed justinemmanuelmercado closed 4 years ago

justinemmanuelmercado commented 4 years ago

Specifically for this line, it needs a reference to itself.

https://github.com/ScaleLeap/amazon-mws-api-sdk/blob/ee978e0955a6b127d02e836d96b9a8f9a9f1c2dd/src/sections/products.ts#L142-L143

I've tried using lazy like this

import { lazy } from 'purify-ts'

//...

interface FeeDetail {
  FeeType: AvailableFeeTypes
  FeeAmount: MoneyType
  FeePromotion?: MoneyType
  TaxAmount?: MoneyType
  FinalFee: MoneyType
  IncludedFeeDetailList?: FeeDetail
}

const FeeDetail: Codec<FeeDetail> = Codec.interface({
  FeeType: oneOf(Object.values(FeeType).map((x) => exactly(x))),
  FeeAmount: MoneyType,
  FeePromotion: optional(MoneyType),
  TaxAmount: optional(MoneyType),
  FinalFee: MoneyType,
  IncludedFeeDetailList: optional(lazy(() => ensureArray('IncludedFeeDetail', FeeDetail))),
})

But typescript nags me about FeeDetail the interface not being equal to what's beeing calculated by Codec

Any help appreciated, @gigobyte

gigobyte commented 4 years ago

Try putting the lazy codec last:

IncludedFeeDetailList: optional(ensureArray('IncludedFeeDetail', lazy(() =>FeeDetail)))
justinemmanuelmercado commented 4 years ago

TS is complaining :/

Type 'Codec<{ FeeType: string; FeeAmount: { Amount: number | undefined; CurrencyCode: CurrencyCodeEnum; }; FeePromotion: { Amount: number | undefined; CurrencyCode: CurrencyCodeEnum; } | undefined; TaxAmount: { Amount: number | undefined; CurrencyCode: CurrencyCodeEnum; } | undefined; FinalFee: { Amount: number | undefined; CurrencyCode: CurrencyCodeEnum; }; IncludedFeeDetailList: FeeDetail[] | undefined; }>' is not assignable to type 'Codec<FeeDetail>'.
  The types returned by 'decode(...)' are incompatible between these types.
    Type 'Either<string, { FeeType: string; FeeAmount: { Amount: number | undefined; CurrencyCode: CurrencyCodeEnum; }; FeePromotion: { Amount: number | undefined; CurrencyCode: CurrencyCodeEnum; } | undefined; TaxAmount: { Amount: number | undefined; CurrencyCode: CurrencyCodeEnum; } | undefined; FinalFee: { Amount: number | undefined; CurrencyCode: CurrencyCodeEnum; }; IncludedFeeDetailList: FeeDetail[] | undefined; }>' is not assignable to type 'Either<string, FeeDetail>'.
      Type '{ FeeType: string; FeeAmount: { Amount: number | undefined; CurrencyCode: CurrencyCodeEnum; }; FeePromotion: { Amount: number | undefined; CurrencyCode: CurrencyCodeEnum; } | undefined; TaxAmount: { Amount: number | undefined; CurrencyCode: CurrencyCodeEnum; } | undefined; FinalFee: { Amount: number | undefined; CurrencyCode: CurrencyCodeEnum; }; IncludedFeeDetailList: FeeDetail[] | undefined; }' is not assignable to type 'FeeDetail'.ts(2322)

Any ideas? If none, it's probably alright as an unknown array. Since Amazon's own API doesn't seem to follow the docs itself. Thanks for the help!

gigobyte commented 4 years ago

Your interface is wrong though, it says IncludedFeeDetailList?: FeeDetail but the codec is IncludedFeeDetailList?: FeeDetail[], as mentioned in the error you posted. That is because of ensureArray.

justinemmanuelmercado commented 4 years ago

Ohh yeah you're right! I don't know why I didn't see that earlier.

TS still complained after though so I just copy pasted whatever was in the error and weirdly enough this is what worked for TS

interface FeeDetail {
  FeePromotion: MoneyType | undefined
  TaxAmount: MoneyType | undefined
  FinalFee: MoneyType
  FeeType: string
  FeeAmount: MoneyType
  IncludedFeeDetailList: FeeDetail[] | undefined
}

const FeeDetail: Codec<FeeDetail> = Codec.interface({
  FeeType: string,
  FeeAmount: MoneyType,
  FeePromotion: optional(MoneyType),
  TaxAmount: optional(MoneyType),
  FinalFee: MoneyType,
  IncludedFeeDetailList: optional(
    ensureArray(
      'IncludedFeeDetail',
      lazy(() => FeeDetail),
    ),
  ),
})

If I tried replacing TaxAmount: MoneyType | undefined with TaxAmount?: MoneyType TS complained that they weren't equal.

Here's the commit to the fix if you're interested https://github.com/ScaleLeap/amazon-mws-api-sdk/pull/45/commits/0ed9e9f7db0fd16dc9d6a4abefd18bb8b50e1713

Thank you for the help 👍