- 
      
- 
        Save glenjamin/75a96b45f4bb5c6ac221815d28c548dd to your computer and use it in GitHub Desktop. 
| /* @flow */ | |
| import * as I from "immutable"; | |
| /** | |
| * Define an immutable record intended for holding reducer state | |
| * @param spec - the keys and their default values | |
| * @return a state record factory function | |
| */ | |
| export function defineRecord<T: Object>( | |
| name: string, | |
| spec: T | |
| ): (init: $Shape<T>) => Record<T> { | |
| return I.Record(spec, name); | |
| } | |
| export type Record<T: Object> = RecordMethods<T> & T; | |
| declare class RecordMethods<T: Object> { | |
| get<A>(key: $Keys<T>): A; | |
| set<A>(key: $Keys<T>, value: A): Record<T>; | |
| update<A>(key: $Keys<T>, updater: (value: A) => A): Record<T>; | |
| updateIn<A>(path: Iterable<any>, notSetOrUpdater: A | (value: A) => A, updater?: (value: A) => A): Record<T>; | |
| setIn<A>(path: Iterable<any>, value: A): Record<T>; | |
| deleteIn<A>(path: Iterable<any>): Record<T>; | |
| merge(values: $Shape<T>): Record<T>; | |
| inspect(): string; | |
| toObject(): T; | |
| // add more as needed | |
| } | 
We've been able to get record flow types to work using the newest v4.0.0-RC-2 release and a bug fix to the record types. With these fixes we can do the following:
// create new record "class"
const newRecord = Record({ id: 0, name: '' });
// create a dummy instance of that record to use for typing
const dummyInst = newRecord();
// create the type to use when declaring the interface to a component
type recordInterface = typeof dummyInst;
// export the record "class" to be used for record instance creation
export { newRecord };
When a record instance is created and passed around, the type of the record is actually typeof dummyInst not newRecord.  So in many cases, you create a dummy instance to generate the correct type, even though it may not be used anywhere in the actual javascript.
@ianwcarlson
I've tried to fork Immutable repository and apply mentioned bugfix. It doesn't seem to work.
const Person = Record({
	name: null,
	age: 0,
	isAdult: false,
})
const personInstance = Person()
type TPerson = typeof personInstance
const Animal = Record({
	name: null,
	owner: null,
})
const animalInstance = Animal()
type TAnimal = typeof animalInstance
export const checkAge = (person: TPerson): void => {
	if (person.age >= 18) {
		console.log('ADULT')
	} else {
		console.log('CHILD')
	}
}
export const foobar = () => {
	const person = Person()
	const animal = Animal()
	checkAge(animal)
}
In this example, the Flow doesn't detect wrong type of object passed to checkAge function. It doesn't event detect if I pass a native type there: checkAge(true).
Am I doing something wrong?
I'm also not able to get @ianwcarlson fix working. Has anyone been successful ?
@glenjamin in your example, I'm struggling to understand how you use all of the things that are exported:
export type ThingShapeexport type ThingRecordexport const ThingSo in that example,
thinghas a type ofThingRecord, and so I guessThingis just a function that returns something with a type ofThingRecord.Ah, I think I get it. But I think it might be clearer if
Thingwas renamed tocreateThingRecord:Just to clarify that you're not creating a new
Thingclass, you're calling a plain function that returns aThingRecord.