如何键入检查标称ID

时间:2018-12-17 12:45:32

标签: typescript enums

我正在尝试下面描述的基于枚举的名义键入方法:https://basarat.gitbooks.io/typescript/docs/tips/nominalTyping.html

enum PersonIdBrand {}
export type PersonId = PersonIdBrand & string

interface Person {
  id: PersonId
  firstName: string
  lastName: string
}

我遇到了一个问题,即将类型添加到测试使用的某些工厂方法中。这些帮助程序方法允许创建具有默认值的测试数据,这些默认值可以有选择地覆盖:

const makeTestPerson = ({
  id = 'personId' as PersonId,
  firstName = 'Bob',
  lastName = 'Smith'
}: Partial<Person> = {}): Person => ({
  id,
  firstName,
  lastName
})

const person = makeTestPerson({ lastName: 'Ross' })

但是,tsc给出了错误:

error TS2322: Type 'PersonId' is not assignable to type 'never'.

11   id = 'personId' as PersonId,

如果我改用id: string,则编译不会有任何问题。有什么办法可以使用PersonId来检查这些函数的类型?


更新进行了更多的探索,我认为此策略还有一个更根本的问题:

const maybePersonId: PersonId | undefined = ("personId" as PersonId)

这也失败了:

TS2322: Type 'PersonId' is not assignable to type 'undefined'.

那为什么会失败?当然X应该总是可以分配给X | undefined吗?

1 个答案:

答案 0 :(得分:1)

我认为,自编写该代码以来,打字稿已改变了它处理空(或它认为是空类型)的并集和交集的方式。我找不到能改变行为的PR,但是如果找到它,我会尝试将其发布(我找不到PR,但中断发生在2.9)

对于品牌类型,compiler team使用的交集类型仅包含一个额外的成员,而不是枚举的交集:

export type Path = string & { __pathBrand: any };

我只会采用这种方法:

export type PersonId = { __personIdBran: any } & string

interface Person {
  id: PersonId
  firstName: string
  lastName: string
}

const makeTestPerson = ({
  id = 'personId' as PersonId,
  firstName = 'Bob',
  lastName = 'Smith'
}: Partial<Person> = {}): Person => ({
  id,
  firstName,
  lastName
})

const person = makeTestPerson({ lastName: 'Ross' })