我可以指定一个属性还需要另一个属性吗?

时间:2018-05-24 16:24:58

标签: typescript

这是一个例子。假设我不控制数据格式。

type Thing = {
  name: string
}

// if you canJump, you need to specify howHigh
type Jump = {
  canJump: true
  howHigh: number
}

// MightJump Things either jump or don't 
type MightJump = Thing | (Thing & Jump)

const thing: MightJump = {
  name: 'hi',
  canJump: true,
  // howHigh: 5, // how do I make commenting this out an error?
}

因此,理想情况下,对于类型为MightJump的值,如果只设置了name,则没关系,但如果设置了canJumphowHigh,则另一个那对也是必需的。

这在TypeScript中是否可行?如果没有,那么需要对编译器进行哪种改变才能支持它?我对限制的确切性质非常感兴趣。

据我所知,Thing | (Thing & Jump)会产生一种类型,其中canJumphowHigh都是可选的,只需要name

更新:使用artem的答案:

type OptNever<T> = {
    [K in keyof T]?: never
}

type AllOrNone<T> = T | OptNever<T>

type MightJump = Thing & AllOrNone<Jump>

3 个答案:

答案 0 :(得分:1)

您需要确保联合的类型不兼容

type Thing = {
  name: string
}

// if you canJump, you need to specify howHigh
type Jump = {
  canJump: true
  howHigh: number
}

// MightJump Things either jump or don't 
type MightJump = (Thing & { canJump?: false } )| (Thing & Jump)

const thing: MightJump = {
  name: 'hi',
  canJump: true,
  // howHigh: 5, // error
}

这对于检查额外的proepries如何为工会起作用有点古怪。通常,如果为对象文字指定了额外的属性,编译器会抱怨,但如果属性属于任何类型的并集,则不会。所以你的文字可以赋予Thing一些额外的属性。如果我们明确地将其与Thing不兼容,则会收到错误。

答案 1 :(得分:1)

您可以通过为其提供可选的never类型来禁止在联合类型成员中存在属性:

type Thing = {
  name: string
}

// if you canJump, you need to specify howHigh, and vice versa
type JumpOrNot = { canJump?: never; howHigh?: never} | {
  canJump: true
  howHigh: number
}

// MightJump Things either jump or don't 
type MightJump = Thing & JumpOrNot

const thing: MightJump = {
  name: 'hi',
  canJump: true,
  // error
  // Type '{ name: string; canJump: true; }' is not assignable to type 'MightJump'.
  //    Type '{ name: string; canJump: true; }' is not assignable to type 'Thing & { canJump: true; howHigh: number; }'.
  //      Type '{ name: string; canJump: true; }' is not assignable to type '{ canJump: true; howHigh: number; }'.
  //        Property 'howHigh' is missing in type '{ name: string; canJump: true; }'.
}

const thing1: MightJump = {
  name: 'thing1'
}

const thing2: MightJump = {
  name: 'thing2',
  canJump: true,
  howHigh: 5, 
}

答案 2 :(得分:1)

一种方法是使用否定类型,例如:

type CantJump = {
   canJump?: undefined
   howHigh?: undefined
}

然后您的MightJump类型将

type MightJump = Thing & ( Jump | CantJump )

这样就可以强制执行这两个属性,也可以不执行任何属性。

unlike关键字目前有一个proposal,可能允许这样的内容:

type MightJump = Thing & ( Jump | unlike Jump )

然而,正在等待更多反馈,这意味着没有足够的支持。