Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to define a generic type in flow that have all the fields optional of specified type

We can define a generic type in typescript very easily that can have all fields optional with respect to passed generic type. Such type of query are very usefull in type definition to define mongo queries's result as we may not need to get all fields and can validate through optional type specification.

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"
}

How to define same thing using Flow. We are able to use $Keys. but not able to get its type while defining another type as we have done in type script. -- [P in keyof T]?: T[P]; We are not able to get P in Flow. 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"
}

Actual We are trying to write a type specification for Query. We can't give null or undefined for not specified keys as well.

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}
}

This query will return some result as follow

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

which can be of Document Type

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

So we can write a function as following

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

It is very straightforward in TypeScript. So I guess there should be way around as well in Flow.

like image 553
Rohit Bansal Avatar asked Jan 29 '18 05:01

Rohit Bansal


2 Answers

You can use $Shape utility:

Copies the shape of the type supplied, but marks every field optional

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

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

Another approach would be "spreading" the type (sorry can't find any documentation on it besides changelog):

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

type Partial<T> = { ...T };

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

Now it is truly partial and you can skip the keys.

like image 192
Aleksey L. Avatar answered Nov 19 '22 16:11

Aleksey L.


You can get close with $ObjMap<T, F> which applies function type F to every property of 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
};

In this case, however, you still can't skip keys, but can add null or undefined to their values.

like image 21
EyasSH Avatar answered Nov 19 '22 14:11

EyasSH