Аргумент против опций в Typescript

На основе этого вопроса множество аргументов и объект параметров

Мне интересно, как это относится к Typescript. Я хотел бы принять решение, чтобы:

Плюсы и минусы, которые я нашел сейчас:

  • Typescript может довольно хорошо обрабатывать необязательные аргументы, но я не считаю удобным полагаться на порядок параметров и иметь длинный список аргументов.

  • Использование объекта option — это хорошо, но для каждого объекта потребуется создать интерфейс (?), что, на мой взгляд, перегрузит код, и я не знаю, какая документация/подсказки будут сгенерированы тогда.


person Flavien Volken    schedule 05.10.2015    source источник
comment
Я не уверен, что вы имели в виду под перегрузкой кода, но интерфейс для объекта параметров - это просто хорошая практика. Если бы вы этого не сделали, вы, вероятно, все равно написали бы большой комментарий, объясняющий это.   -  person thoughtrepo    schedule 05.10.2015
comment
Под перегрузкой кода я имел в виду большой блок кода, описывающий интерфейс для одного объекта option.   -  person Flavien Volken    schedule 05.10.2015


Ответы (1)


На мой взгляд, то же самое относится и к TypeScript. Не полагайтесь на то, что IDE даст вам подсказки о том, что делает код. Лучше всего, чтобы код говорил вам, что он делает.

Чем больше у вас аргументов, тем менее читаемым становится ваш код

Возьмите следующий код:

sendMsg("Poem", "I sing of brooks, of blossoms, birds and bowers.", new Date(2015, 9, 20));

Мы могли бы сказать, что первый аргумент — это заголовок, а второй аргумент — это тело, но что делает третий аргумент? Что означает здесь дата?

Мы должны посмотреть на сигнатуру функции, чтобы увидеть:

function sendMsg(title: string, body: string, dateToSend = new Date())

Итак, теперь мы знаем, что такое третий параметр, но даже несмотря на то, что мы используем TypeScript, нам все равно пришлось провести некоторое исследование и посмотреть на сигнатуру функции. В качестве альтернативы мы могли бы навести указатель мыши на вызов функции для нашей среды разработки, чтобы сообщить нам, но это все еще не идеально.

Слишком много аргументов затрудняет внесение изменений и увеличивает вероятность ошибки

Теперь предположим, что мы хотели добавить новый обязательный параметр даты с именем dateToSendAgain. Сигнатура нашей функции меняется на это:

function sendMsg(title: string, body: string, dateToSendAgain: Date, dateToSend = new Date())

Проблема в том, что наш первоначальный вызов функции не вызывает ошибку компиляции, и смысл изменился:

// now creates a message with dateToSendAgain = new Date(2015, 9, 20)
// and dateToSend = new Date()
sendMsg("Poem", "I sing of brooks, of blossoms, birds and bowers.", new Date(2015, 9, 20));

Несмотря на то, что изначально мы планировали, что dateToSend будет new Date(2015, 9, 20), теперь это new Date(), и, возможно, мы не хотели, чтобы dateToSend было new Date(2015, 9, 20).

Вместо этого используйте объект со свойствами

Мы могли бы решить все это, если бы наша исходная сигнатура функции использовала объект со свойствами (обратите внимание, что интерфейс не требуется):

function sendMsg(options: { title: string; body: string; dateToSend?: Date; dateToSendAgain: Date; }) {
    // we now have to define our default values here though...
    // if we use destructuring it's not too bad:
    const {title, dateToSend = new Date()} = options;
    // ...rest of function body omitted...
}

Таким образом, наш исходный код выглядел бы так:

sendMsg({
    title: "Poem", 
    body: "I sing of brooks, of blossoms, birds and bowers.", 
    dateToSend: new Date(2015, 9, 20)
});

... что очень легко быстро понять, что происходит.

Кроме того, когда мы добавим dateToSendAgain, это будет очень просто, и мы получим ошибку компиляции, информирующую нас о необходимости обновить все наши вызовы функций новым обязательным свойством:

sendMsg({
    title: "Poem", 
    body: "I sing of brooks, of blossoms, birds and bowers.", 
    dateToSend: new Date(2015, 9, 20),
    dateToSendAgain: new Date(2015, 10, 20)
});

Предложение

Мое предложение было бы:

  1. Используйте несколько параметров, когда их не слишком много, и вы можете понять значение каждого аргумента, взглянув на имя функции.
  2. В противном случае используйте объект со свойствами.
  3. Смешивание этих двух вместе нормально, если это читабельно.

Документация по свойствам объекта

TypeScript использует JSDoc для завершения кода, поэтому вы можете использовать этот синтаксис для документирования свойств объекта. Прочитайте здесь, как это задокументировать.

К сожалению, это не дает мне описания свойств объекта при завершении кода в Visual Studio 2013 с TS 1.6.

Однако использование интерфейса, похоже, работает:

/**
 * The options for sendMsg
 */
interface SendMsgOptions {
    /**
    * The title of the message
    */
    title: string;
    // etc...
}

Изменение заголовка функции:

function sendMsg(options: SendMsgOptions)

Затем при его использовании вы можете увидеть комментарий в завершении кода:

Завершение кода параметров сообщения

person David Sherret    schedule 05.10.2015
comment
Хорошо, в большинстве случаев я бы помещал необязательные аргументы в объект опции. Теперь TS может комментировать свойство объекта, чтобы дать подсказку? Ф.э. /@body содержание вашего сообщения/ ? - person Flavien Volken; 05.10.2015
comment
@FlavienVolken у меня не работает. Я добавил раздел «Документация по свойствам объекта» в ответ с более подробной информацией об этом. - person David Sherret; 05.10.2015
comment
В этом случае я бы просто сделал интерфейс и прокомментировал свойство указанного интерфейса. Вы можете поместить комментарии JSDoc прямо в список аргументов, но они должны быть на нескольких строках и выглядеть некрасиво. - person thoughtrepo; 06.10.2015
comment
@thoughtrepo Я согласен. Кстати, можете ли вы привести простой пример того, как прокомментировать свойство интерфейса? Я действительно думаю о @param {string} employee.name - The name of the employee., но это означает, что мне придется вручную указывать тип параметра (в комментарии) вместо того, чтобы использовать тип самого аргумента. Я, очевидно, предпочел бы, чтобы код явно генерировал правильный тип в документе. Изменить хорошо, это выглядит только /** Ваше описание */ перед определением свойства. Большое спасибо! - person Flavien Volken; 06.10.2015
comment
@FlavienVolken да, это только это. Я пошел вперед и обновил сообщение в любом случае. - person David Sherret; 06.10.2015
comment
Я заметил, что мне разрешено устанавливать значение по умолчанию для аргумента параметров, как у вас выше, вот так... makeCube(options: { width: number, depth: number, height: number } = {width:15,depth:15,height:15}) { } Целесообразно ли это? - person Jeremy Foster; 25.03.2016
comment
@JeremyFoster конечно, или вы могли бы сделать что-то вроде этого: makeCube({ width = 15, depth = 15, height = 15 }) { /* use width, depth, and height here */ } (см. Другой пример здесь) - person David Sherret; 28.03.2016
comment
@JeremyFoster они все еще печатаются, просто неявно - person David Sherret; 29.03.2016