流程:要求多态类型具有 属性

Flow: Require that polymorphic type has property

我正在尝试正确键入一个函数,该函数使用 Flow 泛型(或多态)类型将对象数组分页为 graphql/Relay-style "page" 对象。

这是一个简化的例子:

type DBNode = {
  uid: string
}

type Student = DBNode & {
  username: string
}

const students = [{
  uid: '123',
  username: 'user-one',
}, {
  uid: '345',
  username: 'user-two',
}]

type Classroom = DBNode & {
  room: number
}

const classrooms = [{
  uid: '234',
  room: 666,
}, {
  uid: '456',
  room: 667,
}]

type Edge<T> = {
  cursor: string,
  node: T
}

const itemToEdge = <T>(item: T): Edge<T> => ({
  cursor: item.uid,
  node: item
})

type Page<T> = {
  pageInfo: {
    count: number,
  },
  edges: Array<Edge<T>>
}        

const assemblePage = <T>(items: Array<T>): Page<T> => ({
  pageInfo: {
    count: items.length,
  },
  edges: items.map(itemToEdge)
})

const studentPage = (): Page<Student> => {
  return assemblePage(students)
}

const classroomPage = (): Page<Classroom> => {
  return assemblePage(classrooms)
}

我收到的错误是:

cursor: item.uid,
                   ^ Cannot get `item.uid` because property `uid` is missing in `T` [1].
References:
34: const itemToEdge = <T>(item: T): Edge<T> => ({
                                 ^ [1]

是否可以确保多态类型 T 始终是具有 uid 字段的对象?

或者,我尝试输入 assemblePageitemToEdge 来要求项目属于 DBNode 类型,这导致:

38:   node: item            ^ Cannot return object literal because `DBNode` [1] is incompatible with `T` [2] in property `node`.
References:
35: const itemToEdge = <T>(item: DBNode): Edge<T> => ({
                                 ^ [1]
31:   node: T            ^ [2]

Demo

编辑:这是演示的工作版本,感谢@Aleksey L 的帮助!

Working Demo

您可以为泛型类型参数定义约束:

const itemToEdge = <T: DBNode>(item: T): Edge<T> => ({
  cursor: item.uid,
  node: item
})
const assemblePage = <T: DBNode>(items: Array<T>): Page<T> => ({
  ...
})

来自docs

Generics allow you to hold onto the more specific type while adding a constraint