Как определить ключ свойства неизвестного объекта в typescript

#javascript #typescript #vue.js

#javascript #машинописный текст #vue.js

Вопрос:

С помощью Vue composition API мы создали следующий составной:

 import { computed, reactive, SetupContext, ref } from '@vue/composition-api'

export const useApplications = (root: SetupContext['root']) => {
  const applications = reactive({
    1: {
      name: ref(root.$t('app1.name')),
      description: ref(root.$t('app1.description')),
      formName: 'app1form',
    },
    2: {
      name: ref(root.$t('app2.name')),
      description: ref(root.$t('app2.description')),
      formName: 'app2form',
    },
  })

  const getApplication = (id: string) => {
    return applications[id]
  }

  return {
    applications: computed(() => applications),
    getApplication,
  }
}
 

Хотя код работает нормально, он генерирует ошибку TS:

@typescript-eslint/no-unsafe-return: небезопасный возврат любого введенного значения

При наведении курсора мыши на applications раздел становится ясно, что typescript распознает типы, за исключением имени свойства ( 1 ): введите описание изображения здесь

Нужно ли нам создавать интерфейс для решения этой проблемы и нужно ли переопределять каждое свойство в интерфейсе? Я пробовал что-то подобное, но это неверно:

 interface IApplication {
  [key]: string {
    name : string
    description: string
    formName: string
  }
}
 

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

1. Из любопытства, зачем использовать объект с цифровыми клавишами, а не массив?

2. Для ограничений с массивами в composition API в Vue 2

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

4. Сначала я использовал an array . Но есть проблемы с этим подходом для системы реактивности Vue в Vue 2. В любом случае спасибо за помощь, очень признателен.

Ответ №1:

TypeScript обычно не вводит данные, поэтому они могут быть проиндексированы любым строковым ключом. Как вы говорите, вы можете определить для него интерфейс:

 interface IApplications {
    [key: string]: {
        name : string;
        description: string;
        formName: string;
    };
}
// ...
const applications: IApplications = ...
 

Или вы можете просто использовать тип для части объекта и использовать встроенный Record тип для applications :

 interface IApplication {
    name : string;
    description: string;
    formName: string;
}
// ...
const applications: Record<string, IApplication> = ...
 

Или объединение этих двух:

 interface IApplication {
    name : string;
    description: string;
    formName: string;
}
type IApplications = Record<string, IApplication>;
 

(Или вы можете встроить IApplication часть. Или… 🙂 )

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

1. Спасибо, это было именно то, что я искал. Я просто надеялся, что мне не придется переопределять свойства name , description и formName поскольку они уже известны TS с помощью автоматической интерпретации. Но, похоже, нам нужно создать полный объект.

2. @DarkLite1 — Да, было бы неплохо, если бы он мог вывести эту часть. Может быть, это возможно (так много), я просто не сразу вижу это. 🙂

Ответ №2:

В соответствии со структурой параметров reactive функции, интерфейс может быть определен как :

 interface IApplication {
  [key:string]:{
        name : string
       description: string
       formName: string
  }
}
 

и

 const applications = reactive<IApplication>({ ...
                                      
 

Но я хочу предложить другой подход, который определяет tha applications как reactive параметр, который имеет массив в качестве значения:

 
import { computed, reactive, SetupContext, ref ,toRef} from '@vue/composition-api'
interface IApplication {
    name : string
    description: string
    formName: string
  }

export const useApplications = (root: SetupContext['root']) => {
  const state= reactive<Array<IApplication>>({ applications :
    [{
      name: ref(root.$t('app1.name')),
      description: ref(root.$t('app1.description')),
      formName: 'app1form',
    },
     {
      name: ref(root.$t('app2.name')),
      description: ref(root.$t('app2.description')),
      formName: 'app2form',
    }],
  })

  const getApplication = (index: number) => {
    return state.applications[index]
  }

  return {
    applications: toRef(state,'applications'),
    getApplication,
  }
}