Как убрать неявное приведение разных классов в Typescript, даже если у них одна сигнатура
class A {
field: number;
}
class B {
field: number;
}
function f(arg: A) {
arg.field = 5
}
////
const a = new A()
const b = new B()
f(a)
f(b) // WHY???
Вот такой код проходит все проверки на typecheck, не помогает даже strict mode. Если поменять название переменной в одном из классов - будет выдавать ошибку, значит такое неявное приведение появляется, только если интерфейсы классов полностью совпадают. Может есть какая-то настройка компилятора для таких случаев? Как убрать такое неявное приведение?
Ответы (1 шт):
В TypeScript используется структурная типизация, то есть типы считаются совместимыми, если структура описываемых ими объектов совпадает. Номинальная типизация (когда тип объекта зависит от того как он объявлен, а не от его непосредственной структуры) в тс не предусмотрена, однако возможно реализовать нечто похожее на неё. Для такого существует паттерн Branded Types (брендированные типы), он заключается в задании незначимых в рантайме, но отличимых при компиляции различий для типов.
Пример:
class A {
field!: number & { __brand?: "A" };
}
class B {
field!: number & { __brand?: "B" };
}
function f(arg: A) {
arg.field = 5
}
////
const a = new A()
const b = new B()
f(a)
f(b) // Ошибка, типы поля field не совпадают
a.field = 5 // Присваивать обычные числа допустимо
const field: number = b.field // Как и присваивать в обычные числа
Однако, я бы не советовал вам злоупотреблять подобным. Лучше примите существование структурной типизации и задумайтесь, действительно ли есть разница какой из 2х классов придёт в вашу функцию.