简体   繁体   English

打字稿区分联合类型无法识别

[英]Typescript discriminated union type not recognized

I am trying to build an Angular 2/ngrx application based on the example app found at https://github.com/ngrx/example-app/ . 我正在尝试基于在https://github.com/ngrx/example-app/找到的示例应用程序来构建Angular 2 / ngrx应用程序。 I am exporting action types as a discriminated union 我将动作类型导出为有区别的联盟

export const ActionTypes = {
  QUERY: type('[Games] Query'),
  QUERY_COMPLETE: type('[Games] Query Complete'),
  INVALIDATE: type('[Games] Invalidate'),
  SELECT: type('[Games] Select'),
  LOAD_NEXT_PAGE: type('[Games] Load Next Page'),
  LOAD_NEXT_PAGE_COMPLETE: type('[Games] Load Next Page Complete'),

};

export class QueryAction implements Action {
    type = ActionTypes.QUERY;

    constructor(public payload: string) {}
}

export class QueryCompleteAction implements Action {
    type = ActionTypes.QUERY_COMPLETE;

    constructor(public payload: Game[]) {}

}

export class LoadNextPageCompleteAction implements Action {
    type = ActionTypes.LOAD_NEXT_PAGE_COMPLETE;

    constructor(public payload: Game[]) {}
}

export class LoadNextPageAction implements Action {
    type = ActionTypes.LOAD_NEXT_PAGE;

    constructor() {}
}

export class InvalidateAction implements Action {
    type = ActionTypes.INVALIDATE;

    constructor(){}
}

export class SelectAction implements Action {
    type = ActionTypes.SELECT;

    constructor(public payload: number) {}
}

export type Actions = QueryAction | QueryCompleteAction | InvalidateAction | SelectAction | LoadNextPageAction | LoadNextPageCompleteAction;

And passing these to the reducer function, discriminating based on the type property as follows: 并将它们传递给reducer函数,根据type属性进行区分,如下所示:

export function reducer(state = initialState, action: game.Actions): State {
  switch (action.type) {
    case game.ActionTypes.LOAD_NEXT_PAGE:
    case game.ActionTypes.QUERY: {
      return Object.assign({}, state, {loading: true});
    }
    case game.ActionTypes.QUERY_COMPLETE: {
      return {
        games: action.payload,
        offset: action.payload.length,
        loading: false,
        selectedGameId: null
      }
    }
    case game.ActionTypes.LOAD_NEXT_PAGE_COMPLETE: {
      return {
        games: [...state.games, ...action.payload],
        offset: state.offset + action.payload.length,
        loading: false,
        selectedGameId: state.selectedGameId
      }
    }
    case game.ActionTypes.SELECT: {
      return Object.assign({}, state, {selectedGameId: action.payload});
    }
    default: {
      return state;
    }
  }
}

This fails to compile with the error (among other errors) 这无法与错误一起编译(以及其他错误)

Type 'string | number | Game[]' is not assignable to type 'Game[]'.
Type 'string' is not assignable to type 'Game[]'.
Property 'length' does not exist on type 'string | number | Game[]'.
Property 'length' does not exist on type 'number'

Am I doing something wrong or not understanding how discriminated unions work? 我是在做错事还是不了解受歧视的工会的工作方式? My understanding was that the switch statement should narrow down the possible types of action.payload so it is guaranteed to be the correct type. 我的理解是,switch语句应缩小action.payload的可能类型,以确保它是正确的类型。 It seems to be comparing to the types of all of the members of the union, instead of only the one with the matched type. 它似乎是在与工会中所有成员的类型进行比较,而不只是与匹配类型的成员进行比较。

The project is using Typescript v2.1.6 该项目正在使用Typescript v2.1.6

See this github issue and pull request . 请参阅此github问题提出请求

Starting with breaking changes in TypeScript 2.1+, string literal types are always widened to strings unless assigned to immutable const variables or readonly properties. 从TypeScript 2.1+中的重大更改开始,除非将字符串文字类型分配给不可变的const变量或只读属性,否则它们始终会扩展为字符串。 This means things like switch (action.type) statements leveraging discriminated unions stop working with the current example-app patterns. 这意味着像switch(action.type)语句那样利用已区分的并集停止使用当前的示例应用程序模式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM