Когда в интерфейсе определен строковый литерал, я получаю неожиданное поведение.
interface IFoo {
value: 'foo' | 'boo';
}
Когда я реализую интерфейс в классе, я получаю ошибку:
class Foo implements IFoo {
value = 'foo';
}
Я получаю сообщение об ошибке: «Значение» свойства в типе «Foo» не может быть присвоено тому же свойству в базовом типе «IFoo». Но "foo" - правильное значение для строкового литерала.
С другой стороны:
class Boo implements IFoo {
value;
constructor() {
this.value = 'foo';
this.value = 'boo';
this.value = 'koo'; // must be an error Boo doesn't implement IFoo
}
}
const test = new Boo();
test.value = 'koo';
Этот код не вызывает ошибок, но Boo.value
имеет тип any
. Я ожидал получить ошибку, что Boo не реализует IFoo, но ошибки нет.
Единственный правильный способ, который я обнаружил, - это реализовать классы таким образом:
class Koo implements IFoo {
value: 'foo' | 'boo' = 'foo';
}
Поэтому мне пришлось объявить enum:
enum Doos { foo = 'foo', boo = 'boo' }
interface IDoo {
value: Doos;
}
class Doo implements IDoo {
value = Doos.foo;
}
const test = new Doo();
test.value = Doos.boo;
Я понимаю это, потому что компилятор ts получил тип Doo.value из присвоенного значения в объявлении поля. Похоже, что объявлять поля строковых литералов в интерфейсах бесполезно, или я что-то делаю не так. А также выяснил, что классы могут реализовывать интерфейсы с любым типом для полей, так что это зависит от разработчика.