машинописный текст: добавление свойств к классу для альтернатив в типе - PullRequest
1 голос
/ 09 июля 2020

У меня есть тип, представляющий собой дизъюнкцию строк:

export type Category = 'people' | 'projects' | 'topics' | 'tools'

Я объявляю индекс как:

interface Entry {
  ...
}
type IPostEntryIndex = {
  [name in Category]: Entry
}

Как мне объявить свойства класса, соответствующие названиям категорий?

const categories: Category[] = ['people', 'projects', 'topics', 'tools']

class PostEntryIndex implements IPostEntryIndex {
  // what goes here so that `PostEntryIndex` has an attribute
  // for each category in Category?

  constructor () {
    categories.map(cat => this[cat] = new Entry())
  }
}

Обновление : конечно, я могу просто явно объявить категории. Я ищу ответ DRY, не требующий обновления, если я добавлю категорию. (Примечание: сделать массив categories не повторять Category тоже было бы неплохо. Думаю, я мог бы использовать для этого перечисление.)

Ответы [ 2 ]

1 голос
/ 09 июля 2020

Насколько мне известно, не существует синтаксиса, который объявляет набор свойств в классе. Таким образом можно добавить индексную подпись , но не объединение строковых литералов. Очевидно, вы можете добавить их вручную, но я полагаю, дело в том, что вы этого не хотите.

Единственное, что вы можете сделать, - это использовать объявление, объединяющее с добавить свойства в интерфейс экземпляра класса. Когда вы пишете class PostEntryIndex {}, он создает значение с именем PostEntryIndex, которое является конструктором класса, и интерфейс с именем PostEntryIndex, соответствующий индексу класса. И вы можете использовать слияние интерфейсов, чтобы добавить любые свойства, которые вы хотите ... например:

interface PostEntryIndex extends IPostEntryIndex { }
class PostEntryIndex {
  constructor() {
    categories.map(cat => this[cat] = new Entry())
  }
}

Обратите внимание, что это позволяет обойти строгую проверку инициализации свойств класса , которая идет с --strict режим, поэтому вы не можете полагаться на компилятор, чтобы жаловаться на неинициализированные свойства. (На самом деле это используется здесь в ваших интересах, поскольку компилятор не понимает, что цикл по categories служит для инициализации всех соответствующих свойств.)

Также обратите внимание, что как только вы объедините интерфейс таким образом, предложение implements особенно излишне, поэтому я избавился от него. (Оказывается, предложения implements никогда не нужны; система структурных типов TypeScript не требует, чтобы вы объявляли это A implements B, чтобы вы использовали A как B, если они имеют совместимые структуры. .. но я отвлекся)

Все равно посмотрим, работает ли:

const pei = new PostEntryIndex();
pei.projects; // Entry

Выглядит неплохо. Хорошо, надеюсь, что это поможет; удачи!

Детская площадка ссылка на код

0 голосов
/ 09 июля 2020

Следующее принимает https://www.typescriptlang.org/play/

export type Category = 'people' | 'projects' | 'topics' | 'tools'

class Entry {
}

type IPostEntryIndex = {
  [name in Category]: Entry
}


const categories: Category[] = ['people', 'projects', 'topics', 'tools']

class PostEntryIndex implements IPostEntryIndex
{
  people: any;
  projects: any;
  topics: any;
  tools: any;

  constructor () {
    categories.map(cat => this[cat] = new Entry())
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...