Система типов TS является структурной, это означает, что {a: 'a', b: 'b'}
является правильным членом A | B
, потому что она присваивается A
, поскольку имеет все свойства A
и присваивается B
по той же причине. Нет проблем использовать такой объект, где требуется A
или B
, так как он имеет все, что нужно обоим с точки зрения структуры. Рассмотрим следующий фрагмент:
function fOnA(modifier: A) { } // we require only A
const a = { a: '', b: '' } // we create object with additional props
fOnA(a) // no error
Мы можем выполнить проверку типа { a: '', b: '' }
.
type ExtendsA = { a: '', b: '' } extends A ? true : false // evaluates true
type ExtendsB = { a: '', b: '' } extends B ? true : false // evaluates true
Как видите, { a: '', b: '' }
является допустимым объектом, который будет использоваться для A
и для B
.
Понятно, что использование такой конструкции с дополнительными свойствами не вредит, поскольку у нас всегда есть то, что нам нужно.
Случай, когда мы хотим различить, если у нас есть A
или B
- это случай, когда мы должны создать дискриминант, чтобы иметь возможность проверить, какой объект попал внутрь функции. Рассмотрим:
interface A{
kind: 'A', // discriminant
a: string;
}
interface B{
kind: 'B', // discriminant
b: string;
}
function aOrB(modifier: A | B) {}
aOrB({ kind: 'A', a: '' }); // works!
aOrB({ kind: 'B', b: '' }); // works!
aOrB({ kind: 'B', a: '' }); // error as it should be
aOrB({ kind: 'B', b: '', a: '' }); // error as it should be
Я добавил kind
, чтобы различать guish обе версии. Такой подход имеет много преимуществ, так как теперь мы можем легко проверить, есть ли у нас A
или B
, просто проверив kind
.
Другое решение состоит в том, чтобы заблокировать свойства, которые нам не нужны, never
ключевое слово. Обратите внимание:
interface A{
a: string;
b?: never;
}
interface B{
b: string;
a?: never;
}
function aOrB(modifier: A | B) {}
aOrB({ a: '' }); // works!
aOrB({ b: '' }); // works!
aOrB({ a: '', b: ''}); // error as it should be
Добавляя prop?: never;
, я не позволяю объекту проходить требования A
и B
.