spacenear
@spacenear
React Web Developer

Почему расширеный интерфейс в TS не принимается компилятором?

interface Field {
  value: any,
  validation?: FieldValidation
}

interface InputField extends Field {
  value: string,
  placeholder: string,
  textarea?: boolean,
  maxChars?: number,
  type?: 'text' | 'email' | 'password' | 'tel' | 'url',
  dark?: boolean,
  disabled?: boolean,
  onInput?: () => any,
  onKeyDown?: () => any,
  onFocus?: () => any,
  onBlur?: () => any
}


По логике он дожен внизу принимать этот объект потому что он соответствует Field который был расширен InputField

const fields = ref<Record<string, Field>>({
        name: {
          value: '1',
          placeholder: '123'
        },
});


Но компилятор выдает ошибку
603d49037b04b962448851.jpeg
  • Вопрос задан
  • 103 просмотра
Решения вопроса 2
bingo347
@bingo347 Куратор тега TypeScript
Crazy on performance...
Расширение интерфейсов (это именно расширение, а не наследование) работает по принципу И, а в формировании Record Вы от него ожидаете принципа ИЛИ.
Типы в TypeScript подчиняются достаточно строгой математике, за счет которой он способен статически типизировать всю мощь хаоса динамического JavaScript.
Если не брать в расчет способность интерфейсов к слиянию, то расширение интерфейсов можно считать сахаром над операцией & над типами, то есть это:
interface Field {
  value: any,
  validation?: FieldValidation
}

interface InputField extends Field {
  value: string,
  placeholder: string,
  textarea?: boolean,
  maxChars?: number,
  type?: 'text' | 'email' | 'password' | 'tel' | 'url',
  dark?: boolean,
  disabled?: boolean,
  onInput?: () => any,
  onKeyDown?: () => any,
  onFocus?: () => any,
  onBlur?: () => any
}
аналогично этому:
interface Field {
  value: any,
  validation?: FieldValidation
}

type InputField = Field & {
  value: string,
  placeholder: string,
  textarea?: boolean,
  maxChars?: number,
  type?: 'text' | 'email' | 'password' | 'tel' | 'url',
  dark?: boolean,
  disabled?: boolean,
  onInput?: () => any,
  onKeyDown?: () => any,
  onFocus?: () => any,
  onBlur?: () => any
}

А ожидаемую Вами логику можно получить c помощью операции | следующим образом:
interface BaseField {
  value: any,
  validation?: FieldValidation
}

interface InputField extends BaseField {
  value: string,
  placeholder: string,
  textarea?: boolean,
  maxChars?: number,
  type?: 'text' | 'email' | 'password' | 'tel' | 'url',
  dark?: boolean,
  disabled?: boolean,
  onInput?: () => any,
  onKeyDown?: () => any,
  onFocus?: () => any,
  onBlur?: () => any
}

interface SelectField extends BaseField {
  options: string[],
  value: string,
  placeholder: string,
  dark?: boolean,
  disabled?: boolean,
  onSelect?: () => any,
  onKeyDown?: () => any,
  onFocus?: () => any,
  onBlur?: () => any
}

type Field = InputField | SelectField;
const fields = ref<Record<string, Field>>({
        name: {
          value: '1',
          placeholder: '123'
        },
});


P.S. Для одного доклада по TypeScript готовил такой пример:
https://gist.github.com/bingo347/00652993abf31702c...
Если поймете, как оно работает, то познаете большую часть дзена TypeScript
Ответ написан
yarkov
@yarkov
Помог ответ? Отметь решением.
Может вы хотели написать так?
Record<string, InputField>
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы