打字稿中不一致类型的数组

Dan*_*l T 3 typescript

给定类型不一致的数组。例如,这可用于动态呈现 html 元素。

interface IElement {
  type: 'button' | 'input'
  content: Button & Input
}

interface Button {
  text?: string;
  backgroundColor?: string;
}

interface Input {
  value?: string;
  placeholder?: string;
}

const elements: IElement[] = [
  {
    type: 'button',
    content: {
      text: 'Start',
      backgroundColor: 'salmon'
    }
  },
  {
    type: 'input',
    content: {
      value: 'phone',
      placeholder: 'Phone'
    }
  }
]

const newElement = elements.map(element => element.content.backgroundColor)
Run Code Online (Sandbox Code Playgroud)

有没有其他方法可以正确地对它进行类型转换取决于type没有联合的属性?

cca*_*ton 5

在 Typescript 中,标准模式是使用所谓的“可区分联合”。基本上,您可以使用其他语言的地方IElement值,而在 Typescript 中,您尝试使用联合来代替。这允许 Typescript 在您检查type类型保护中的字段值时确定正确的类型。

它可能看起来像这样:

interface Button {
  type: 'button'
  text: string
  backgroundColor: string
}

interface Input {
  type: 'input'
  value: string
  placeholder: string
}

type ElementUnion = Button | Input

const elements: ElementUnion[] = [
  {
    type: 'button',
    text: 'Start',
    backgroundColor: 'salmon'
  },
  {
    type: 'input',
    value: 'phone',
    placeholder: 'Phone'
  }
]

function doSomething (el: ElementUnion) {
  if (el.type === 'button') {
    console.log(el.text) // TS knows this is Button
  } else if (el.type === 'input') {
    console.log(el.placeholder) // TS knows this is Input
  }
}
Run Code Online (Sandbox Code Playgroud)

请注意,我没有将任何属性定义为可选或交集,但是doSomething只要我检查type字段。这就是受歧视工会的力量。

如果你愿意,你仍然可以同时使用继承模式:

type ElementType = 'button' | 'input'

interface IElement {
  type: ElementType
  content: unknown
}

interface Button extends IElement {
  type: 'button'
  content: {
    text: string
    backgroundColor: string
  }
}

interface Input extends IElement {
  type: 'input'
  content: {
    value: string
    placeholder: string
  }
}

type ElementUnion = Button | Input
    
function doSomething (el: ElementUnion) {
  if (el.type === 'button') {
    console.log(el.content.text) // TS knows this is Button
  } else if (el.type === 'input') {
    console.log(el.content.placeholder) // TS knows this is Input
  }
}
Run Code Online (Sandbox Code Playgroud)

打字稿游乐场