2. About me
• Ikai Lan, new to Medium, new to JavaScript
• … hopefully not new to programming
• Based out of San Francisco, but I love New York
City
•
Favorite emoji: 😐
9. Now you need some
rules, before things get
out of hand…
10. The array that wasn’t.
// Before the fix
getLatestPosts(userId) {
if (!userId) {
return Q.resolve(null)
}
// More code here to fetch posts and
// return a Promise
}
11. The array that wasn’t.
// Somewhere several layers up
// the stack
let result = client.getLatestPosts(currentUserId)
result.forEach((value) => { ... })
12. The array that wasn’t.
// Somewhere several layers up
// the stack
let result = client.getLatestPosts(currentUserId)
result.forEach((value) => { ... })
Uncaught TypeError: Cannot read property 'foreach' of
null(…)
13. The array that wasn’t.
getLatestPosts(userId) {
if (!userId) {
return Q.resolve([])
}
// More code here to fetch posts and
// return a Promise
}
14. The array that wasn’t.
getLatestPosts(userId) {
if (!userId) {
return Q.resolve([])
}
// More code here to fetch posts and
// return a Promise
}
[]
15. Yet, the docs …
/**
* @return {Promise<Array<Post>>} A sample of
* the user's posts
*/
getLatestPosts(userId) {
if (!userId) {
return Q.resolve(null)
}
// More code here to fetch posts and
// return a Promise
}
16. Yet, the docs …
/**
* @return {Promise<Array<Post>>} A sample of
* the user's posts
*/
getLatestPosts(userId) {
if (!userId) {
return Q.resolve(null)
}
// More code here to fetch posts and
// return a Promise
}
/**
* @return {Promise<Array<Post>>} A sample of
* the user's posts
*/
18. I want an object!
- var recommendedPostRelationsPromise =
this._postUserService.getVotesForUserId(followedUserId,
recommendedSince)
+ var recommendedPostRelationsPromise =
this._postUserService.getVotesForUserId(followedUserId,
{votedAfter: recommendedSince})
19. I want an object!
- var recommendedPostRelationsPromise =
this._postUserService.getVotesForUserId(followedUserId,
recommendedSince)
+ var recommendedPostRelationsPromise =
this._postUserService.getVotesForUserId(followedUserId,
{votedAfter: recommendedSince})
20. What if that value is
undefined?
/**
* @returns an Array of only recent votes
*/
getVotesForUserId(userId, filterParams) {
// Limit results returned to items greater
// than this parameter
return queryForVotesAfter(
filterParams.recommendedSince)
}
22. Closure Flow
Google Facebook
Type annotations in docs Type annotations inline
Valid JavaScript Requires transformation
Convert entire codebase File-by-file
23. Closure Flow
Google Facebook
Type annotations in docs Type annotations inline
Valid JavaScript Requires transformation
Convert entire codebase File-by-file
24. How do we add types?
‘use strict’ // @flow
First line of a file to annotate
31. server/graph/common/goSocialClient.js:382
382: .then((result: any): Array<T> => {
^^^^^^^^ array type. This type is incompatible with
12: onFulfill?: (value: R) => KewPromise<U> | U,
^^^^^^^^^^^^^^^^^ union: type application of identifier
`KewPromise` | type parameter `U` of call of method `then`. See lib: style-guide/flow-interfaces.js:
12
Member 1:
12: onFulfill?: (value: R) => KewPromise<U> | U,
^^^^^^^^^^^^^ type application of identifier `KewPromise`. See
lib: style-guide/flow-interfaces.js:12
Error:
382: .then((result: any): Array<T> => {
^^^^^^^^ array type. This type is incompatible with
12: onFulfill?: (value: R) => KewPromise<U> | U,
^^^^^^^^^^^^^ KewPromise. See lib: style-guide/flow-
interfaces.js:12
Member 2:
381: return this.request(requestData)
^ type parameter `U` of call of method `then`
Error:
382: .then((result: any): Array<T> => {
^^^^^^^^ array type. This type is incompatible with
373: fetchObjects<T: RpcSchema>(Ctor: Class<T>, options: GoSocialRequestOptions): Promise<T> {
^ some incompatible instantiation of `T`
When flow complains …
39. Remember this?
/**
* @return {Promise<Array<Post>>} A sample of
* the user's posts
*/
getLatestPosts(userId) {
if (!userId) {
return Q.resolve(null)
}
// More code here to fetch posts and
// return a Promise
}
40. We have to define interfaces for
third party libraries
47. create(tag: Tag): Promise<Tag> {
let tag = null;
if (someCondition) {
tag = new Tag()
}
return Q.resolve(tag)
}
No ‘?’ to show that return type is nullable
ERROR
48. create(tag: Tag): Promise<?Tag> {
let tag = null;
if (someCondition) {
tag = new Tag()
}
return Q.resolve(tag)
}
‘?’ shows that return type is nullable
Correct!
49. Now everything this touches
• Has to null check (via a conditional) - subtle
changes in how code works
• Or accept a type ?Tag, which means “nullable
type”
• Adding to existing code can be tricky without
introducing subtle changes
50. But this is also good
• Makes us really think about which methods will
always have a valid object, which will not
• Will lead to better API design long term
51. But it can be confusing
function myNullableString(input: ?string): number {
return input.length;
}
function callerOfMyNullableString(input: string): number {
return myNullableString(input);
}
52. function myNullableString(input: ?string): number {
return input.length;
}
function callerOfMyNullableString(input: string): number {
return myNullableString(input);
}
input: ?string
input: string
This is valid
53. This is not valid
function myArray(input: Array<?string>): number {
return input.length;
}
function callerOfMyArray(input: Array<string>): number
{
return myArrayWithNullableObjects(input);
}
54. Here’s why
function myArray(input: Array<?string>): number
{
input.append(null);
return input.length;
}
function callerOfMyArray(input: Array<string>): number {
return myArrayWithNullableObjects(input);
}
No longer valid!
55. Organizational challenges
• General organization buy-in
• Flow is almost an entirely new language that
people need to learn
• Working against a moving target
• Funny things that happen after merges
56. To recap
• We are finding it hard to scale development
without types
• Adding types to untyped code has a number of
challenges, technical and otherwise
• We believe the payoff will be totally worth it.
57. Thank you!
• Thanks to Kelly, Nick, Gianni for being great
teammates and teaching me everything
• Thanks to Madeline for organizing this great
event!
• Image source: unsplash.com
58. Q&A
• If you come up with someone, just ask one of us!
• Twitter/Medium: @ikai