#typescript
#typescript
Вопрос:
Я запускаю то, что кажется ошибкой неправильного типа при попытке использовать пересечения типов Typescript и различаемые объединения вместе.
Идея заключается в:
Объект должен содержать два логических значения — discriminant_1
и discriminant_2
. Если любое из этих дискриминантных полей является true
, объект должен содержать дополнительное поле — extra_field_1
и extra_field_2
соответственно.
Итак, вот несколько примеров допустимых объектов:
// Neither field is true - no extra fields
{ discriminant_1: false, discriminant_2: false }
// discriminant_1 is true - extra_field_1 present
{ discriminant_1: true, extra_field_1: true, discriminant_2: false }
// both discriminant fields are true - both extra fields present
{ discriminant_1: true, extra_field_1: true, discriminant_2: true, extra_field_2: true }
И недопустимый объект, потому discriminant_2
что есть true
, но extra_field_2
отсутствует
{ discriminant_1: false, discriminant_2: true }
Это приводит к ошибкам компиляции в ожидаемых местах, но эти ошибки сбивают с толку в тех случаях, когда поля не указаны.
Для следующего объекта:
{ discriminant_1: false, discriminant_2: true }
Тип не компилируется, потому что, если discriminant_2
есть true
, extra_field_2
должен быть указан в объекте. Но ошибка типа:
Type '{ discriminant_1: false; discriminant_2: true; }' is not assignable to type 'FullType'.
Type '{ discriminant_1: false; discriminant_2: true; }' is not assignable to type 'Discriminant1_True amp; Discriminant2_True'.
Property 'extra_field_1' is missing in type '{ discriminant_1: false; discriminant_2: true; }' but required in type 'Discriminant1_True'.
Сообщение об ошибке подразумевает, что выводимый тип является Discriminant1_True amp; Discriminant2_True
, несмотря на тот факт, что discriminant_1
есть false
, и говорит, что extra_field_1
отсутствует, хотя на самом деле это то extra_field_2
, что отсутствует.
Ожидаемое сообщение об ошибке:
Type '{ discriminant_1: false; discriminant_2: true; }' is not assignable to type 'FullType'.
Type '{ discriminant_1: false; discriminant_2: true; }' is not assignable to type 'Discriminant1_False amp; Discriminant2_True'.
Property 'extra_field_2' is missing in type '{ discriminant_1: false; discriminant_2: true; }' but required in type 'Discriminant2_True'.
Что укажет программисту на правильное отсутствующее поле.
Возможно ли записать типы таким образом, чтобы сообщения об ошибках, которые возвращаются при построении ошибочных типов, указывали на правильное отсутствующее поле?
Комментарии:
1. Вам следует поискать аналогичную проблему на GitHub, я не думаю, что SO — подходящее место для этого вопроса. Поведение действительно такое, как вы описываете. Если вы добавите правильные поля, это сработает, просто сообщение об ошибке не работает. Я предполагаю, что, поскольку существует несколько возможных дискриминантов, typescript просто выбирает первый член объединения и генерирует ошибки для этого, даже если объект может быть ближе к другому типу в объединении.
2. Спасибо, Тициан! Я просмотрел Github, но не смог найти связанную проблему — однако кто-то указал мне на эту проблему , которая, насколько я могу судить, описывает ту же проблему
3. да, это похоже на точное. Я был уверен, что была аналогичная проблема :). Это в отставании, поэтому в какой-то момент оно может быть исправлено, хотя я подозреваю, что оно не имеет высокого приоритета
Ответ №1:
Позвольте мне дать свои 2 цента, и, надеюсь, кто-то намного мудрее меня (coff @basarat ) сможет рассказать вам еще больше интересных вещей 🙂
Я не уверен, что различимые объединения вполне дают вам то, что вам нужно. Могут быть определены пользователем средства защиты типов. Позвольте мне объяснить. Ваш объект примерно такой:
interface NotTheTypeSafetyYouHopedFor {
discriminant_1: boolean;
extra_field_1?: boolean;
discriminant_2: boolean;
extra_field_2?: boolean;
}
Но вы хотели бы немного усилить типы. Итак, давайте упростим проблему, забыв, что discriminant_2
она и extra_field_2?
существует. Пуф! Они исчезли.
interface False1 {
discriminant_1: false;
}
interface True1 {
discriminant_1: true;
extra_field_1: boolean;
}
type False1OrTrue1 = False1 | True1;
const exampleFalse1: False1 = { discriminant_1: false };
const exampleTrue1: True1 = { discriminant_1: true, extra_field_1: false };
function isTrue1(aFalse1OrTrue1: False1OrTrue1): aFalse1OrTrue1 is True1 {
return aFalse1OrTrue1.hasOwnProperty('extra_field_1')
}
function doSomething(aFalse1OrTrue1: False1OrTrue1) {
if (isTrue1(aFalse1OrTrue1)) {
console.log(aFalse1OrTrue1.extra_field_1); // succeeds as this is a True1
} else {
console.log(aFalse1OrTrue1.extra_field_1); // compile error as this is a False1
}
}
Я подозреваю, что это подход, который может не масштабироваться напрямую, учитывая характер вашего вопроса (т.Е. discriminant_2 и т. Д.)
Но если бы каждое свойство в объекте было a False1OrTrue1
, то, возможно, оно соответствовало бы вашим потребностям? Надеюсь, это поможет. Guida говорит «привет» 🙂
Комментарии:
1. Проблема не в функциональности типа. Тип функционирует так, как ожидает OP, он позволяет объектам OP считать допустимый проход, а ошибки в объектах OP считает недопустимыми (по крайней мере, в моем чтении, OP не стесняйтесь поправлять меня в этом). Единственная проблема заключается в том, что сообщение об ошибке для некоторых недопустимых объектов кажется запутанным. Ошибка должна быть там, проблема заключается только в сообщении
2. Спасибо, Джон! Я не часто использовал определяемые пользователем средства защиты типов, поэтому было бы здорово увидеть их вариант использования. К сожалению, я не думаю, что это сработает в моем случае. Мой фактический код имеет три дискриминанта объединения строк, каждый со своим собственным набором значений, и каждый из которых определяет различный набор полей в конечном объекте. Код действительно работает, т. Е. Он компилируется / не компилируется, когда объект является допустимым / недопустимым. Просто сообщения об ошибках в недопустимом случае не кажутся правильными. Кто-то указал мне на эту проблему , которая выглядит связанной
3. Рад попытаться помочь! Похоже, что проблема с GitHub очень актуальна. Приятно видеть, что вы пытаетесь ввести Type-Fu; системы ввода вызывают привыкание 😊