Typescript Typeguard 检查数组是否属于类型

Typescript Typeguard check if array is of type

我想写一个类型保护来检查数组的所有子项是否都是类型 T 从而使它成为一个数组,其中 T 是一个通用类型

TS Playground

// Assume arr of any type but Array
const arr: any[] = [
  {
    foo: "bleh1",
    bar: 1
  },
  {
    foo: "bleh2",
    bar: 2
  },
]

interface newType {
  foo: string
  bar: number
}

// Check that arr is an array of newType , ie arr: newType[]
const isArrayOf = <T,>(arr: any): arr is Array<T> => {
  // TypeScript mastery needed here
  return true
}

if(isArrayOf<newType>(arr)){
  arr
}

你能做的最好的事情是:

const arr: NewType[] = [
  {
    foo: "bleh1",
    bar: 1
  },
  {
    foo: "bleh2",
    bar: 2
  },
]

interface NewType {
  foo: string
  bar: number
}

type TypeOfArrayElements<T> = T extends Array<infer U> ? U : never;

type ArrayType = TypeOfArrayElements<typeof arr>;

TypeScript 永远无法猜测类型为 any[] 的数组实际上包含 NewType 个元素。与 TypeScript 中的所有内容一样,type predicates 是静态的,不会 return 基于运行时作为参数传递的动态类型。但是,如果您将其键入为 NewType[],则可以从中提取 NewType 类型。

编辑 1:

这个答案有两个缺点(在评论中提到)

  • 属性 不需要拥有它就可以存在于对象 x = {a: 1}; y = Object.create(x); y.b = 2
  • 该功能需要您手动枚举对象的所有键。因此会引入人为错误

我认为该解决方案在特定情况下仍可用作解决方法

原文:

如果数组 anewType[] 类型,那么考虑 x = a[0] 的每个元素都是 newType 类型。 xnewType 类型,因为 x 满足 newType.

类型的所有属性和方法

因此如果反转,如果 x y z 是类型 newType 并且它们是数组 a 的唯一和所有元素,因此a 的每个元素都是 newType 类型,满足 anewType[]

类型的条件
// Check if obj has all keys props[]
const hasAllProperties = <T,>(obj: any, props: (keyof T)[]): obj is T => {
  return props.every((prop) => {
    // console.log(prop)
    return Object.prototype.hasOwnProperty.call(obj, prop)})
}

// Check that arr is an array of newType , ie arr: newType[]
const isArrayOf = <T,>(obj: any[], props: (keyof T)[]): obj is T[] => {
  // Check if every elements have all keys in props
  return obj.every((ele) => {
    // console.log(ele)
    return hasAllProperties<T>(ele,props)
  }
  )
}

if (isArrayOf<newType>(arr, ["foo", "bar"])) {
  console.log("arr is of newType[]")
}

TS Playground