Skip to content

Instantly share code, notes, and snippets.

@glenjamin
Last active May 4, 2020 16:50
Show Gist options
  • Save glenjamin/75a96b45f4bb5c6ac221815d28c548dd to your computer and use it in GitHub Desktop.
Save glenjamin/75a96b45f4bb5c6ac221815d28c548dd to your computer and use it in GitHub Desktop.
Flow types for immutable records.
/* @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
}
@ianwcarlson
Copy link

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.

@jake-daniels
Copy link

@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?

@davidlygagnon
Copy link

davidlygagnon commented Jul 21, 2017

I'm also not able to get @ianwcarlson fix working. Has anyone been successful ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment