M
M
Maxim Zolotoy2021-03-01 23:04:43
typescript
Maxim Zolotoy, 2021-03-01 23:04:43

Why is the extended interface in TS not accepted by the compiler?

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
}


Logically, it should accept this object at the bottom because it corresponds to the Field that was extended by the InputField

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


But the compiler throws an error
603d49037b04b962448851.jpeg

Answer the question

In order to leave comments, you need to log in

1 answer(s)
D
Dmitry Belyaev, 2021-03-02
@spacenear

The extension of interfaces (this is exactly an extension, not inheritance) works according to the AND principle , and in the formation of Record you expect the OR principle from it .
The types in TypeScript are subject to sufficiently strict mathematics, due to which it is able to statically type the full power of the chaos of dynamic JavaScript.
If you do not take into account the ability of interfaces to merge , then the extension of interfaces can be considered sugar over the operation & over types, that is:

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
}
similar to this:
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
}

And the logic you expect can be obtained using the operation | in the following way:
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'
        },
});

PS For one report on TypeScript, I prepared this example:
https://gist.github.com/bingo347/00652993abf31702c...
If you understand how it works, you will know most of the Zen of TypeScript

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question