Избегайте приведения машинописи внутри коммутатора - PullRequest
0 голосов
/ 20 ноября 2018

Рассмотрим следующий код:

interface FooBarTypeMap {
  FOO: FooInterface;
  BAR: BarInterface;
}

type FooBarTypes = "FOO" | "BAR";

export interface FooBarAction<T extends FooBarTypes> {
  type: T;
  data: FooBarTypeMap[T];
}

const doSomthingBasedOnType = (action: FooBarAction<FooBarTypes>): void => {
  switch (action.type) {
    case "FOO":
      FooAction((action as FooBarAction<"FOO">));
  }
};

const FooAction = (action: FooBarAction<"FOO">): void => {
  //do something with action.data
};

Теперь я хотел бы избежать приведения (действие как FooBarAction <"FOO">), как видно в doSomthingBasedOnType, как само определение, если интерфейс делает этоЕдинственная возможность внутри этого переключателя.Что-то, что я могу изменить в своем коде, чтобы это работало, или это просто ошибка в TypeScript?

1 Ответ

0 голосов
/ 20 ноября 2018

Вам необходимо преобразовать FooBarAction в дискриминационный союз.На данный момент ваша версия FooBarAction не очень строгая, в то время как type должен быть одним из "FOO" | "BAR", а data должен быть одним из FooBarTypeMap[FooBarTypes] = FooInterface | BarInterface, между ними нет никакой связи.Таким образом, это может быть разрешено:

let o : FooBarAction2<FooBarTypes> = {
  type: "BAR",
  data: {} as FooInterface
}

Версия распознаваемого объединения будет выглядеть следующим образом:

export type FooBarAction = {
  type: "FOO";
  data: FooInterface;
} | {
  type: "BAR";
  data: BarInterface;
}

const doSomthingBasedOnType = (action: FooBarAction): void => {
  switch (action.type) {
    case "FOO":
      FooAction(action);
  }
};

// We use extract to get a specific type from the union
const FooAction = (action: Extract<FooBarAction, { type: "FOO" }>): void => {
  //do something with action.data
};

Вы также можете создать объединение из объединения типов, используя распределенное поведение условных выражений.типы:

interface FooInterface { foo: number}
interface BarInterface { bar: number}
interface FooBarTypeMap {
  FOO: FooInterface;
  BAR: BarInterface;
}

type FooBarTypes = "FOO" | "BAR";

export type FooBarAction<T extends FooBarTypes> = T extends any ? {
  type: T;
  data: FooBarTypeMap[T];
}: never;


const doSomthingBasedOnType = (action: FooBarAction<FooBarTypes>): void => {
  switch (action.type) {
    case "FOO":
      FooAction(action);
  }
};

const FooAction = (action: FooBarAction<"FOO">): void => {
  //do something with action.data
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...