如何在流中定义具有指定类型的所有可选字段的泛型类型

Posted

技术标签:

【中文标题】如何在流中定义具有指定类型的所有可选字段的泛型类型【英文标题】:How to define a generic type in flow that have all the fields optional of specified type 【发布时间】:2018-07-07 18:18:30 【问题描述】:

我们可以很容易地在 typescript 中定义一个泛型类型,它可以让所有字段对于传递的泛型类型都是可选的。这种类型的查询在类型定义中非常有用,可以定义 mongo 查询的结果,因为我们可能不需要获取所有字段,并且可以通过可选的类型规范进行验证。

https://www.typescriptlang.org/docs/handbook/advanced-types.html

interface Person 
    name: string;
    age: number;


type Partial<T> = 
    [P in keyof T]?: T[P];


const p : Partial<Person> = 
    name:"A"

如何使用 Flow 定义相同的事物。我们可以使用 $Keys。但在定义另一种类型时无法获得它的类型,就像我们在类型脚本中所做的那样。 -- [P in keyof T]?: T[P];我们无法在 Flow 中获得 P。 https://flow.org/en/docs/types/utilities/#toc-keys

type Person = 
    name: string,
    age: number;    


type Partial<T> = 
    [$Keys<T>] : 1;  // doubt here how to get type of prop comes in left


const p : Partial<Person> = 
    name:"A"

实际我们正在尝试为 Query 编写类型规范。我们也不能为未指定的键提供 null 或 undefined。

type Department = 
    _id : string,
    name : string,
    type : string


type Person = 
    _id : string,
    name : string,
    age : number,
    department : Department


type Query <T> = 
    [P in keyOf T ]?: 1 | Query<T[P]> 


type Document<T> = 
    [P in keyOf T ]?: T[P] | Document<T[P]>     


const personDepartments  : Query<Person> = 
    name:1, department :name:1

这个查询将返回一些结果如下

_id:"1",name:"abc",department:name:"xyz"

可以是文档类型

const a : Document<Person> = _id:"1",name:"abc",department:name:"xyz"

所以我们可以编写如下函数

function getResult<T>(query:Query<T>) : Document<t> 
    // code here to query and get result

在 TypeScript 中非常简单。所以我想Flow中也应该有解决方法。

【问题讨论】:

你好团队:有可能吗? TL;DR - 没有答案。但只是好奇,所有字段都是可选的类型有什么意义?无论如何,在使用它之前,您都需要对它们进行空检查。这里唯一的限制是添加不在Person 类型中的字段,但这是您首先需要的吗?我们的方法是我们总是假设 DB 返回mixed,因为应用程序。无法控制 DB,因此我们永远无法 100% 确定来自 DB 的内容。在我们得到一个mixed-type 结果后,我们应用一个映射器来确保到达的数据是准确的预期类型。如果不是“意外数据”,则触发处理程序。 谢谢维克多。当我们定义 mongo 查询并在视图上显示结果时,我们实际上有一个用例。我们必须在视图(ui 端)上显示更少的列。所以我们需要创建一个可以期望更少列的类型定义。而且我们不能在主类型中使每一列都是可选的,因为在保存文档时,必须具有强制列的值。但我认为它不应该是流式的,因为它起源于类型脚本,并且它的大部分语法与打字稿相似。所以应该有一种我们没有找到的流程方式可能是由于没有记录。 “所以我们需要创建一个可以期望更少列的类型定义” - 所以,您正在尝试创建另一种类型(即 PersonForView),其中所有字段都是可选的,对吧?如果是,那么我的问题仍然存在——为什么你需要一个所有字段都是可选的类型?视图仍然必须对所有字段进行空检查。你需要这种类型吗? “它起源于类型脚本” - 我目前没有证据,但我怀疑 Flow 起源于 TS - 它们非常不同,它们使用完全不同的类型推理算法并用不同的语言编写(分别为 OCaml 和 TS )。 感谢 Viktor 的澄清。为视图定义一个类型似乎是重复的工作并且容易出错,因为没有办法验证它是否是主类型。 【参考方案1】:

您可以使用$Shape 实用程序:

复制所提供类型的形状,但将每个字段标记为可选

type Foo = 
  A: string,
  B: number,
  C: string
;

const t: $Shape<Foo> = 
  A: 'a'
;

另一种方法是“传播”类型(抱歉,除了changelog,找不到任何关于它的文档):

type Foo = 
  A: string,
  B: number,
  C: string
;

type Partial<T> =  ...T ;

const t: Partial<Foo> = 
  A: 'a'
;

现在它确实是部分的,您可以跳过键。

【讨论】:

谢谢阿列克西。我们会尝试的。【参考方案2】:

您可以接近$ObjMap&lt;T, F&gt;,它将函数类型F 应用于T 的每个属性。

type Foo = 
  A: string,
  B: number,
  C: string
;

function makeOptional<T>(t: T): ?T 
  return t;


type PartialFoo = $ObjMap<Foo, typeof makeOptional>;

const t: PartialFoo = 
  A: 'a',
  B: null,
  C: undefined
;

但是,在这种情况下,您仍然不能跳过键,但可以将 nullundefined 添加到它们的值中。

【讨论】:

感谢 EyasSH。实际我们正在尝试为 Query 编写类型规范。我们也不能为未指定的键提供 null 或 undefined 。正如我编辑我的问题以解释我们想要什么。直接在 TypeScript 中是可能的

以上是关于如何在流中定义具有指定类型的所有可选字段的泛型类型的主要内容,如果未能解决你的问题,请参考以下文章

泛型类的可选方法参数的类型

Scala的泛型

GetMethod 的 Type[] 以获取具有两个参数和一个类型参数的泛型方法

TypeScript 中具有泛型类型参数的泛型类型的替代方案

如何将方法的泛型类型限制为打字稿中的对象?

Java中的泛型理解