Невозможно использовать пользовательский тип внутри интерфейса

#typescript

#typescript

Вопрос:

Кажется, я не могу понять, почему я не могу использовать пользовательский тип внутри интерфейса.

У меня есть следующее определение:

 type Operation = 'update'|'remove'|'add'
interface Rule {
  op: Operation
  path:string
  value?:any
}

function applyDiff<Output>(rules: Rule[], obj: object): Output;
  

но я получаю Type 'string' is not assignable to type 'Operation' сообщение об ошибке при этом неудачном тестировании:

 const obj = {a: {b:1, c:2}}
const rules = [
  {op: 'update', path: 'a.c', value:10},
] 
const result = applyDiff(rules, obj)
  

но этот код работает просто отлично:

 function fn(x: number, y: 'add'|'remove'|'update'){
  return x > 1 amp;amp; y === 'add'
  
}
const result = fn(1, 'remove')
  

Чего мне здесь не хватает? Я был бы признателен за любое полезное руководство по этому вопросу. Спасибо.

Ответ №1:

Во-первых, простое решение:

 const rules: Rule[] = [
        // ^------^
  {op: 'update', path: 'a.c', value:10},
] 
  

Но почему это не работает с самого начала? Потому что предполагаемый тип rules является {op: string; path: string; value: number}[] , и существует множество string s, которые не являются ни одним из значений в Operation объединении. Объекты и массивы изменяемы, поэтому ничто не мешает op изменять значение (например, помещать новый объект в массив или изменять существующий объект в массиве) между определением rules и передачей его applyDiff .

Это также предлагает некоторые другие решения:

  1. Передайте массив непосредственно в функцию:

     const result = applyDiff([
      {op: 'update', path: 'a.c', value:10},
    ], obj);
      

    Здесь значения не могут меняться между определением массива и передачей его в applyDiff , поэтому выводится более узкий тип {op: 'update'; path: 'a.c'; value: 10}[] .

  2. Используйте const утверждение, чтобы явно сузить тип правила:

     const rules = [
      {op: 'update', path: 'a.c', value:10} as const,
                                        // ^-------^
    ];
      

    Это сообщает компилятору, что вы считаете этот объект неизменяемым, что приводит его к выводу о более узком типе для rules тоже. Вместо этого вы могли бы явно сузить тип op :

     const rules = [
      {op: 'update' as const, path: 'a.c', value:10},
                // ^-------^
    ];
      

    с аналогичными эффектами.

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

1. Это определенно работает, но если это правильный ответ, то это работает так, как ожидалось, и мой вопрос отчасти недействителен. Моя проблема в том, что это определение является частью библиотеки, и я тестирую то, что пользователь получает «из коробки», чего в данном случае немного. С таким же успехом я мог бы оставить op тип равным string . Спасибо за быстрый ответ.

2. Я только что увидел предложение с const — я искал что-то подобное. Высоко ценится.

3. @DejanToteff какое определение является частью библиотеки? Похоже, что вопрос, возможно, не полностью отражал контекст.

4. часть с appyDiff объявлением. Но предложение с const работает для меня просто отлично. Я не упомянул контекст, поскольку считаю, что это не имеет отношения к делу, но я обязательно включу его в свой следующий вопрос.