TypeScript: дискриминируемые объединения с необязательными значениями
даны следующие типы:
interface FullName {
fullName?: string
}
interface Name {
firstName: string
lastName: string
}
type Person = FullName | Name;
const p1: Person = {};
const p2: Person = { fullName: 'test' };
const p3: Person = { firstName: 'test' }; // Does not throw
const p4: Person = { badProp: true }; // Does throw, as badProp is not on FullName | Name;
Я бы ожидал p3
приведет к ошибке компилятора, как firstName
присутствует без lastName
, но это не ... это ошибка или ожидается?
кроме того, создание FullName.fullName необходимые результаты в p3
(и p1
) вызывает ошибки.
2 ответов
тип в вашем вопросе не является, в обычном смысле, дискриминируемым Союзом - ваши члены Союза не имеют общего, необязательного буквального свойства дискриминантный.
Итак, как отметил @Alex в своем ответе, ваш союз несколько похож на
type Person = {
fullName?: string
firstName?: string
lastName?: string
}
таким образом, он может быть инициализирован с { firstName: 'test' }
с истинными дискриминируемыми объединениями вы получаете логику для проверки необязательных свойств, а также проверки того, что литерал объекта может укажите только известные свойства:
interface FullName {
kind: 'fullname';
fullName?: string
}
interface Name {
kind: 'name';
firstName: string
lastName: string
}
type Person = FullName | Name;
const p1: Person = {kind: 'fullname'}; // ok
const p2: Person = {kind: 'fullname', fullName: 'test' }; // ok
проверка необязательного свойства:
const p3: Person = {kind: 'name', firstName: 'test' };
ошибка:
Type '{ kind: "name"; firstName: string; }' is not assignable to type 'Person'.
Type '{ kind: "name"; firstName: string; }' is not assignable to type 'Name'.
Property 'lastName' is missing in type '{ kind: "name"; firstName: string; }'.
проверка дополнительного свойства:
const p5: Person = { kind: 'fullname', bar: 42 }
ошибка:
Type '{ kind: "fullname"; bar: number; }' is not assignable to type 'Person'.
Object literal may only specify known properties, and 'bar' does not exist in type 'Person'.
, как выяснил @JeffMercado, проверка типа все еще немного выключена:
const p6: Person = { kind: 'fullname', firstName: 42 }; // no error. why?
Я бы рассмотрел возможность публикации проблемы для проекта GitHub typescript.
во-первых, ваш интерфейс FullName
содержит только одно необязательное свойство, которое в основном делает его соответствующим чему-либо. Затем, когда вы делаете тип объединения с ним, результирующий тип будет совместим со всем.
, есть еще одна проблема с объявлением и назначением литеральных объектов, и это то, что вы можете только объявить известные свойства: почему я получаю ошибку " литерал объекта может указывать только известные свойства"?
таким образом, вы можете сделать это без каких-либо проблем:
var test = { otherStuff: 23 };
const p4: Person = test;
но не это
const p4: Person = { otherStuff: 23 };
а в твоем случае firstName
является известным свойством FullName | Name
, так что все ок.
и как @artem ответил,discriminated unions
имеют особое значение в typescript, помимо регулярных союзов, требующих специальных структурных предположений.