打字稿类型不匹配

时间:2019-12-08 11:43:35

标签: typescript typescript-typings

由于某种原因,即使类型对我来说我仍然会出错:


    //* ListWithCards has base of List but contains {cards: Card[]} field
    //* ListWithCardsWithCustomFieldValues has base of List but the card type is {cards: CardWithCustomFieldValue[]}

    export const recover = (tApi: TrelloRestApi, reportError: CreateErrorReport) => (withException: boolean) => async <
      P extends List | ListWithCards | ListWithCardsWithCustomFieldValues | string,
      T = P extends string ? List : Exclude<P, 'string'>
    >(
      param: P
    ): Promise<T> => {
      //* tApi.get.list takes string as an argument and returns List type
      //* isString is a typeguard that checks if passed param is string
      //* List results in:  List | P
      const list = isString(param) ? await tApi.get.list(param) : param;
      try {
        if ('closed' in list && list.closed) {
          await tApi.update.list(list.id, { closed: false });
          if (withException) await reportError(eTools.listRecovererErrorCard(list));
        }

        //* error: Spread types may only be created from object types
        return { ...list, closed: false };
      } catch (error) {
        await reportError(error);
        //* error: Type 'List | P' is not assignable to type 'T'.
        // * Type 'List' is not assignable to type 'T'.
        //* 'List' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'List | ListWithCards | ListWithCardsWithCustomFieldValues'
        return list;
      }
    };


我希望在检查param是否为字符串列表之后,最终会得到:List | ListWithCards | ListWithCardsWithCustomFieldValues,但在传播时会抱怨list不是对象,而对象是那一点,或者至少应该这样看。

这也是来自stackblitz的代码示例 https://stackblitz.com/edit/typescript-yyaj4u?file=index.ts

请注意,我在项目中使用的是打字稿3.7.2版本,但即使在具有确定不同版本的stackblitz上,该错误仍然会出现。

1 个答案:

答案 0 :(得分:0)

这里有一些冲突。

  1. 您有返回变量list,其类型为P | List
  2. TPT extends P extends string ? List : Exclude<P, "string">
  3. 的子类型
  4. 您的退货类型为T

因此,您不能通过此声明返回类型P | List,因为TP的子类型。我认为您应该完全省略T

export const listRecoverer = (
  tApi: TrelloRestApi,
  reportError: (error: Error) => Promise<void>
) => (withException: boolean) => async <
  P extends List | ListWithCards | ListWithCardsWithCustomFieldValues | string
>(
  param: P
): Promise<P | List> => {
  const list = isString(param) ? await tApi.get.list(param) : param;

  try {
    if ("closed" in list && list.closed) {
      await tApi.update.list(list.id, { closed: false });
      if (withException) await reportError(new Error(""));
    }

    return { ...list, closed: false };
  } catch (error) {
    await reportError(error);

    // P extends string | List | ListWithCards | ListWithCardsWithCustomFieldValues
    // T extends P extends string ? List : Exclude<P, "string">
    // const list: P | List

    return list;
  }
};