在接口中定义时,字符串文字类型字段分配错误

问题描述 投票:1回答:1

在接口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.valueany类型。我期望得到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从字段声明中的赋值获得D​​oo.value类型。看起来在接口中声明字符串文字类型的字段是没用的,或者我做错了什么。并且还发现类可以为字段实现类型为any的接口,因此这取决于开发人员。

typescript typescript-types
1个回答
1
投票

问题是你期望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';
}
© www.soinside.com 2019 - 2024. All rights reserved.