如何在Typescript中从常量定义字符串字面量联合类型

108

我知道我可以定义字符串联合类型来限制变量只能是可能的字符串值之一:

type MyType = 'first' | 'second'
let myVar:MyType = 'first'

我需要构建一个类似于常量字符串的类型,例如:

const MY_CONSTANT = 'MY_CONSTANT'
const SOMETHING_ELSE = 'SOMETHING_ELSE'
type MyType = MY_CONSTANT | SOMETHING_ELSE

但出于某些原因它不起作用,它显示错误信息:MY_CONSTANT指向一个值,但在此处被用作类型

为什么TypeScript允许第一个示例,但不允许第二个示例?我使用的是TypeScript 3.4.5。


2
听起来你真正想要的是一个枚举(enum)...? - T.J. Crowder
5
你想要的是 type MyType = typeof MY_CONSTANT | typeof SOMETHING_ELSE。类型(仅存在于设计时间)和值(在运行时存在)之间有很大区别。 - jcalz
当我感到类型和值之间的混淆时,我经常向人们传达这个答案。链接 - jcalz
@T.J.Crowder 考虑过这个问题,但我有一些在其他地方定义的常量字符串需要使用。 - Can Poyrazoğlu
@CanPoyrazoğlu - 好的,那么Titian的答案就是你想要的。 - T.J. Crowder
4个回答

147
要获取变量的类型,您需要使用typeof类型运算符:
const MY_CONSTANT = 'MY_CONSTANT' // must be const, no annotation. let or var will not work
const SOMETHING_ELSE = 'SOMETHING_ELSE' // must be const, no annotation. let or var will not work
type MyType = typeof MY_CONSTANT | typeof SOMETHING_ELSE

Playground

提示:

由于人们在使用此代码时似乎存在很多困惑。 const 很重要。如果您使用其他类型的声明(letvar),则最终类型将为字符串。只有 const 可以保留字符串字面量类型。

提示2:

为了使该解决方案有效,您必须const 上指定任何类型注释,并让编译器推断常量的类型(例如,这将不起作用const MY_CONSTANT:string = 'MY_CONSTANT'


1
@CanPoyrazoğlu 的 'test' 同时是一个值和一个类型(一个字符串文字类型),根据定义(就像类是一个值,构造函数是一个类型,实例类型) - Titian Cernicova-Dragomir
17
typeof MY_CONSTANT 将会检查它是否为某个 string 类型,而不是特指 MY_CONSTANT - Knut Holm
1
如果有人能解释一下对这个答案的负评,我会很感激。我坚持认为这个答案仍然能够完成它应该完成的任务,并且回答了原始问题。如果有人对此有意见,请让我知道。 - Titian Cernicova-Dragomir
5
@JonasRosenqvist,请阅读评论和注释。请检查相关的游乐场链接。如果您使用 const,则文字类型将被保留并且类型检查将按您的期望工作,并且不会兼容所有字符串。如果您有一个反例,请让我看看。很抱歉如果我听起来有点生气,但是这个答案因无缘由而不断受到投票而且变得非常恼人。不确定我能做什么来更清楚地表明需要使用 const - Titian Cernicova-Dragomir
3
@TitianCernicova-Dragomir - 你是对的,我犯了一个错误,声明常量时应该这样写: const MY_CONSTANT:string = 'MY_CONSTANT' 指定常量类型后,它可以接受任何字符串。抱歉,你会得到我的赞! - Jonas Rosenqvist
显示剩余11条评论

21

您也可以在这种情况下使用枚举。例如:

// Define enum.
enum myConstants {
  MY_CONSTANT = 'my_constant',
  SMTH_ELSE = 'smth_else'
}

// Use it in an interface for typechecking.
interface MyInterface {
  myProp: myConstants
}

// Example of correct object - no errors.
let a: MyInterface = {
  myProp: myConstants.MY_CONSTANT
}

// Incorrect value - TS reports an error.
let b: MyInterface = {
  myProp: 'John Doe'
}

枚举类型更多信息


1
这正是我在寻找的内容。 - Joel Stransky

13

枚举类型相当适用:

export enum ITEM_TYPES {
    TYPE1 = 'text',
    TYPE2 = 'image'
}

export type IItemType = ITEM_TYPES.TYPE1 | ITEM_TYPES.TYPE2

然后在代码中,可以使用ITEM_TYPES来进行各种运行时比较:

if (type === ITEM_TYPES.TYPE1){
}

0

谢谢Fatih。刚刚读了你的文章,非常详细和有用! - Can Poyrazoğlu
1
我很高兴我的帖子能够帮到你,谢谢! - FatihAziz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接