我想要一个类型来描述一组字符串,以及一个带有键的对象,以便于访问所述字符串。
初始化const TwoWords
时,所有键的值都被类型声明为TwoWords,然后DoSomething(TwoWords.Foo)
编译,但switch语句中的typeguard不能按预期工作 - {的类型默认情况下,{1}}不是word
。
never
但是,如果我为每个type TwoWords = 'foo' | 'bar';
const TwoWords = {
Foo: 'foo' as TwoWords,
Bar: 'bar' as TwoWords
};
function DoSomething(word: TwoWords) {
switch (word) {
case TwoWords.Foo:
break;
case TwoWords.Bar:
break;
default:
let typeInferenceCheck: never = word; // Type '"foo"' is not assignable to type 'never'
}
}
DoSomething(TwoWords.Foo);
DoSomething('bar');
键的值使用字符串文字类型断言,则默认情况下TwoWords
的类型为word
,正如我所料。
never
如果type TwoWords = 'foo' | 'bar';
const TwoWords = {
Foo: 'foo' as 'foo',
Bar: 'bar' as 'bar'
};
function DoSomething(word: TwoWords) {
switch (word) {
case TwoWords.Foo:
break;
case TwoWords.Bar:
break;
default:
let typeInferenceCheck: never = word; // OK
}
}
DoSomething(TwoWords.Foo);
DoSomething('bar');
和'foo'
是更长的字符串(例如,整个句子),我不想复制它们 - 它太冗长了。是否有另一种方法可以使用字符串键控枚举,从switch语句(或if / else链)中的类型推断透视图中按预期运行?
根据Madara Uchiha的回答,您可以使用TypeScript 2.4字符串枚举获得正确的类型推断(如选项2中所示),但这些不可与字符串文字互换。
'bar'
(见GitHub issue #15930 about string literal assignment to TypeScript 2.4 string enum)
我正在寻找另一个允许我拥有的选项:
DoSomething('bar'); // Type '"bar"' is not assignable to parameter of type 'TwoWords'
EnumLikeObject.Foo === 'foo'
let thing: EnumLikeObject = 'foo'
异议&讨论
答案 0 :(得分:5)
如果你想等待并忍受一点,
TypeScript 2.4将真正的字符串枚举带到比赛场地:
enum TwoWords {
Foo = 'foo',
Bar = 'bar'
}
function DoSomething(word: TwoWords) {
switch (word) {
case TwoWords.Foo:
break;
case TwoWords.Bar:
break;
default:
let typeCheck: never = word; // OK
}
}
这可以让你获得两全其美。
答案 1 :(得分:2)
我想我明白了。至少:
DoSomething
接受"foo"
或"bar"
。并满足您的标准
TwoWords.Foo === 'foo'
所以不用多说:
const TwoWords = (function () {
const Foo = 'foo';
const Bar = 'bar';
const ret = {
Foo: Foo as typeof Foo,
Bar: Bar as typeof Bar,
};
return ret;
})()
type TwoWords = typeof TwoWords[keyof typeof TwoWords];
然后我有一个灯泡时刻
namespace TwoWords2 {
export const Foo = "foo";
export const Bar = "bar";
}
type TwoWords2 = typeof TwoWords2[keyof typeof TwoWords2]
// didn't test this, not sure if it actually updates the
// original object or just returns a frozen copy
Object.freeze(TwoWords2);
在我看来,这并不是一个缺点,因为它仍然在类型检查器和VS代码中引发错误,但TwoWords2.Bar = "five"
实际上是有效的,因为命名空间被编译为一个简单的对象。但这就是打字稿的工作方式。显然第一个代码也有这个问题,但它不会抛出类型错误,所以第二个代码是优越的,IMO。