Компилятор Машинописного Текста Не Применяет Универсальные Методы

#reactjs #typescript #generics

Вопрос:

Вопрос

У меня есть модель редуктора с действием, которое принимает payload ожидаемую форму { id: string, newValues: Partial<A_or_B> } . В приведенном ниже коде принудительное применение типа A_or_B не применяется при newValues объявлении встроенного; однако, если я объявляю newValues заранее и назначаю ему свойства, ограничения применяются. Как я могу применить ограничения A_or_B даже в том случае, если newValues он объявлен встроенным?

Проблемный Код

 import { useContext } from "react";
import { AppDispatchContext } from "../src/AppProvider";
import { ActionTypes, A_or_B } from "./interfaces";

export default function App() {
  const dispatch = useContext(AppDispatchContext);

  const x: Partial<A_or_B> = {};
  // Property 'color' does not exist on type
  // 'Partial<A> | Partial<B>'.
  // Property 'color' does not exist on type 'Partial<A>'.
  x.color = "red";

  dispatch({
    type: ActionTypes.POINT_UPDATED,
    // why can I assign a color to Partial<A>|Partial<B> if 'color'
    // only exists on B?
    payload: { id: "x", newValues: { color: "red" } }
  });
}
 

Ссылка на CodeSandbox

Ссылка на CodeSandbox Здесь

Комментарии:

1. Для справки, вот более простой случай typescriptlang.org/play?strictPropertyInitialization=false#code/… Это та же самая проблема?

2. @Алекс Уэйн Вроде как…

Ответ №1:

Это распространенная проблема, с которой большинство людей сталкиваются при работе с union типами в typescript. Некоторые относятся к ним так, как если бы они были типами пересечения, в то время как некоторые хотели бы, чтобы они вели себя скорее как взаимоисключающие типы.

Однако typescript имеет две различные интерпретации типов объединений, в зависимости от вашего варианта использования.

Свойства

При попытке доступа к свойству типа объединения вы можете получить доступ только к свойствам, которые являются общими для всех членов объединения. Другой способ сказать это состоит в том, что у вас есть доступ только к пересечению свойств членов союза.

Это может быть полным ртом, но документы typescript дают хорошую аналогию, чтобы объяснить это:

Например, если бы у нас была комната с высокими людьми в шляпах и другая комната с испанцами, говорящими в шляпах, после объединения этих комнат единственное, что мы знаем о каждом человеке, — это то, что он должен быть в шляпе.

Таким образом, в случае доступа к свойствам typescript разрешает доступ только к подмножеству свойств (без каких-либо дополнительных подсказок от пользователя), образуя, таким образом, пересечение.

Членство (он же вывод типа)

Когда дело доходит до вывода типа, компилятор довольно либерально относится к тому, что он позволяет сопоставлять тип объединения. По сути, это говорит о том, что если вы хотите быть частью этой группы, вам просто нужно выглядеть как один из членов этой группы. В этом случае вам не обязательно иметь свойство, соответствующее свойству каждого члена союза.


Возможно, решение вашей проблемы состоит в том, чтобы просто использовать тип пересечения для x :

 const x: Partial<Aamp;B> = {};
x.color = "red"; // works!

...
newValues: x; // also works
 

Это решает проблему как доступа к собственности, так и членства

Ответ №2:

Ограничения на самом деле применяются в вашей полезной нагрузке. Вы можете проверить это, добавив свойство в свой полезный груз, которого нет в типе A или B.

Реальная проблема здесь заключается в выводе типов.

   const x: Partial<A_or_B> = {};
  // Property 'color' does not exist on type
  // 'Partial<A> | Partial<B>'.
  // Property 'color' does not exist on type 'Partial<A>'.
  x.color = "red";
 

x присваивается допустимое значение объединения, но Typescript не может определить, относится ли оно к типу A или B, поэтому x.color его нельзя проверить, поскольку TS считает, что существует вероятность того, что оно может быть типа B.

 payload: { id: "x", newValues: { color: "red" } }
 

newValues явно устанавливается для объекта, который содержит только color то, что означает, что Typescript знает, что это должно быть типа A.

Пример