在接口I中定义的字符串文字类型时会出现意外行为。
interface IFoo {
value: 'foo' | 'boo';
}
当我在类中实现接口时出现错误:
class Foo implements IFoo {
value = 'foo';
}
我收到一个错误:类型'Foo'中的属性'value'不能分配给基类型'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 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 compiller从字段声明中的赋值获得Doo.value类型。看起来在接口中声明字符串文字类型的字段是没用的,或者我做错了什么。并且还发现类可以为字段实现类型为any的接口,因此这取决于开发人员。
问题是你期望implements IFoo
影响类字段的输入方式。它不是。事情发生的方式是类字段的输入就像implements Foo
不存在一样,并且在类类型完全解析之后,检查它是否与实现的接口兼容。以这种方式看待这个,错误是有道理的。
class Foo implements IFoo {
value = 'foo'; // this is typed as string, not as the string literal type and thus is not compatible with value in IFoo
}
class Boo implements IFoo {
// no type, no init, value is typed as any and any is compatible with 'foo' | 'boo'
// use -noImplicitAny to avoid such errors
value;
constructor() {
this.value = 'foo';
this.value = 'boo';
this.value = 'koo'; // 'koo' is compatible with any
}
}
当你使用枚举时,事情是有效的,因为如果我们将enum的值赋给字段,该字段将被输入为枚举。
您可以明确指定value
字段的类型,也可以指定IFoo
接口的类型:
class Foo implements IFoo {
value: IFoo['value'] = 'foo';
}
或者如果该字段是readonly
,它将被输入为字符串文字类型:
class Foo implements IFoo {
readonly value = 'foo';
}