TypeScript: тип свойства несовместим при назначении из универсального типа

Рассмотрим следующий код: (здесь также пример кода https://codesandbox.io/s/hbtew?file=/src/index.ts)

enum Types {TEXT, DATE}

interface TextState {
  type: typeof Types.TEXT
}

interface DateState {
  type: typeof Types.DATE
}

type State = TextState | DateState;

interface GenericProps {
  state: State
}

interface InputProps<AnyState> {
  state: AnyState;
}

function TextInput(props: InputProps<TextState>) {
}

function DateInput(props: InputProps<DateState>) {
}

const props: GenericProps = {state: {type: Types.TEXT}};
/*
Type 'State' is not assignable to type 'TextState'.
  Type 'DateState' is not assignable to type 'TextState'.
    Types of property 'type' are incompatible.
      Type 'Types.DATE' is not assignable to type 'Types.TEXT'
*/
TextInput(props);

const {state} = props;
/*
Type 'State' is not assignable to type 'TextState'.
  Type 'DateState' is not assignable to type 'TextState'
*/
TextInput({state: state});

/* OK */
TextInput({state: {type: Types.TEXT}});

/* OK */
DateInput({state: {type: Types.DATE}});

Как видите, при вызове TextInput(props) произошла ошибка. Не могли бы вы объяснить, как возникла эта ошибка и как исправить код, чтобы вызов TextInput(props) не выдавал ошибки? Цель состоит в том, чтобы иметь возможность сконструировать разные GenericProps, которые отличаются только type и могут быть переданы либо в TextInput(props) (если props = {state: {type: Types.TEXT}}), либо в DateInput(props) (если props = {state: {type: Types.DATE}}), спасибо!

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
0
17
2

Ответы 2

Я бы предложил использовать ключевое слово as, оно обычно решает проблемы с типами. Ты можешь пойти как

varName: Type = anotherVarWithSlightlyDifferentType as Type

В вашем случае этого должно хватить

Не совсем понимаю, что вы имеете в виду. Не могли бы вы указать конкретно?

user1589188 09.04.2021 10:09

Обычно вам нужно «помочь» Typescript понять, что вы проверили тип реквизита, потому что в противном случае вы можете изменить тип состояния.

вы можете решить эту проблему, добавив функцию validateTextProps, которая выглядит так:

function validateTextProps(props: GenericProps): props is InputProps<TextState> {
  return props.state.type === Types.TEXT;
}

const props: GenericProps = { state: { type: Types.TEXT } };
if (validateTextProps(props)){
  TextInput(props);
}

Таким образом, Typescript понимает, что реквизиты имеют правильный тип, и позволяет вам вызывать TextInput (реквизиты).

Другие вопросы по теме