首页 > 解决方案 > 具有多种类型的打字稿,如何确定哪种类型具有某些道具

问题描述

假设我有 3 种类型。A型、B型和C型

typeA 有一个 name 属性,而 typeB 和 typeC 没有

当我用类似的代码渲染它时;

interface propTypes {
 post: typeA | typeB | typeC
}

..... some react code ....
return( 
{post?.name && component})

但它返回错误:“类型 'typeA| typeB | typeC 上不存在属性 'name'

我试过 post instanceof typeA 但它返回一个错误'typeA'只指一种类型,但在这里被用作一个值。

标签: reactjstypescript

解决方案


考虑这个例子:

type typeA = {
  name: string
}

type typeB = {
  surname: string
}

type typeC = {
  age: number
}

type post = typeA | typeB | typeC

interface propTypes {
  post: post
}

const App = ({ post }: propTypes) => {
  post // no autocomplete

  return null
}

之后没有自动完成,post.因为您没有任何常见的道具。

查看文档

如果我们有一个联合类型的值,我们只能访问联合中所有类型共有的成员。

为了使其工作,您应该定义一个typeguard

const isTypeA = (props: unknown): props is typeA => Object.prototype.hasOwnProperty.call(props, 'name')

const App = ({ post }: propTypes) => {
  if (isTypeA(post)) {
    post.name // string
  }

  return null
}

或者,您可以使用in运算符,它与联合非常有效:

const App = ({ post }: propTypes) => {
  if ('name' in post) {
    post.name // string
  }

  return null
}

或者你可以使用StrictUnion类型:

type typeA = {
  name: string
}

type typeB = {
  surname: string
}

type typeC = {
  age: number
}

// credits goes to https://stackoverflow.com/questions/65805600/type-union-not-checking-for-excess-properties#answer-65805753
type UnionKeys<T> = T extends T ? keyof T : never;
type StrictUnionHelper<T, TAll> =
  T extends any
  ? T & Partial<Record<Exclude<UnionKeys<TAll>, keyof T>, never>> : never;

type StrictUnion<T> = StrictUnionHelper<T, T>

type Post = StrictUnion<typeA | typeB | typeC>


interface propTypes {
  post: Post
}


const App = ({ post }: propTypes) => {
  if (post.name) {
    post.name // string
  }

  return null
}

操场


'in' 运算符为我工作请记住,它有自己的缺点:

type typeA = {
  name?: string
}

interface propTypes {
  post: typeA
}


const App = ({ post }: propTypes) => {
  if ('name' in post) {
    post.name.charAt // error
  }

  return null
}

它适用于联合,但不适用于可选属性。


推荐阅读