Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add function statics and object callable properties #55

Merged
merged 8 commits into from Jun 5, 2019
118 README.md
@@ -519,6 +519,8 @@ add("1", "1"); // Ok
add(1, "1"); // Error
```

It is also possible to create function overloads using callable property syntax, see the section [Object callable property](#object-callable-property).

### TypeScript

TypeScript supports both function and method overloading, in both: type definitions (`.d.ts`) and inline alongside code.
@@ -635,6 +637,122 @@ However, Flow implementation is stricter in this case, as B have a property that

Most of the syntax of Flow and TypeScript is the same. TypeScript is more expressive for certain use-cases (advanced mapped types with keysof, readonly properties), and Flow is more expressive for others (e.g. `$Diff`).

## Object callable property

The basic syntax are the same, except Flow has special syntax for the internal call property slot.

Both can be used to annotate function statics.

### Flow

You can use objects with callable properties as functions: [Try Flow](https://flow.org/try/#0PTAEAEDMBsHsHcBQiAuBPADgU1AMVALygDeiooAFAJQBcoAzigE4CWAdgOaIC+A3IgGNYbRqEh18RaoQB8oAEQALLNDjz+QkSlDLVsOo1adCY6ryA)

```js
type F = {
(): string
};
const f: F = () => "hello";
const hello: string = f();
```

An overloaded function is a function with multiple call signatures.
This is supported by Flow. And we list out the different syntaxes here: [Try Flow](https://flow.org/try/#0PTAEAEDMBsHsHcBQiAuBPADgU1AMVALygDeiooAFAJQBcoAzigE4CWAdgOYA0ZoA2nwDGAQ2jQAuuLoU2AVwC2AIyxMqhAHwNm7brwEixkio1adaW0x0QBfZINhtGoSHXxEKADwD8dOUpWgAD4WOmoEmqTkTFgoskxsoB6gXokAdCiwAMranNSgdADkBQDcNohAA)

```js
type F = {
(): string,
[[call]]: (number) => string,
[[call]](string): string
}
const f: F = (x?: number | string) => {
return x ? x.toString() : '';
}
```

Use call property to annotate function statics: [Try Flow](https://flow.org/try/#0PTAEAEDMBsHsHcBQiAuBPADgU1AWSwLawCWAXlgCYBiAhgMYqwBOxN0AKpjgLygDeiUKDr0AFlgBc-QaACQAbQB2AVwIAjLEwC6Ules0yAvgBoZ8+SOjQtWgBR6NTAJS7Vj04eR1YigM4pQSHpGFjYpfCIySloGZlYOLlBeRSSAPmkhYkhQWwBCINjQ6AA6ETpxJwyhQOC4tlKxHn5PIRbQLJyCkPiG8qwlLVBc7l5lRQosSGJFSkqBatAmLBRlJhSuupKy8QGjGQ2i3p3FQeSkkdAABlAAflAARlBdUAAqGsL4+1AAWgenGSWKzW7269W2-ROiEMQA)

```js
type MemoizedFactorialType = {
cache: {
[number]: number,
},
[[call]](number): number,
}
const factorial: MemoizedFactorialType = n => {
if (!factorial.cache) {
factorial.cache = {}
}
if (factorial.cache[n] !== undefined) {
return factorial.cache[n]
}
factorial.cache[n] = n === 0 ? 1 : n * factorial(n - 1)
return factorial.cache[n]
}
```

Reference:

- [Callable Objects](https://flow.org/en/docs/types/functions/#callable-objects-)
- [immer.js](https://github.com/immerjs/immer/blob/master/src/immer.js.flow) uses it to overload the `produce` (default export) function which has multiple call signatures
- [Styled Components](https://github.com/flow-typed/flow-typed/blob/master/definitions/npm/styled-components_v4.x.x/flow_v0.75.x-/styled-components_v4.x.x.js#L242) uses it to separate cases of being called on a string and wrapping a component
- [Reselect Library Definition](https://github.com/flow-typed/flow-typed/blob/master/definitions/npm/re-reselect_v2.x.x/flow_v0.67.1-/re-reselect_v2.x.x.js) contains massive chunks of overloaded call properties

### TypeScript

You can use objects with callable properties as functions: [TypeScript Playground](https://www.typescriptlang.org/play/#src=type%20F%20%3D%20%7B%0D%0A%20%20()%3A%20string%3B%0D%0A%7D%0D%0Aconst%20foo%3A%20F%20%3D%20()%20%3D%3E%20%22hello%22%3B%0D%0Aconst%20bar%3A%20string%20%3D%20foo()%3B)

```ts
type F = {
(): string;
}
const foo: F = () => "hello";
const bar: string = foo();
```

An overloaded function is a function with multiple call signatures.
This is also supported by TypeScript: [TypeScript Playground](https://www.typescriptlang.org/play/#src=type%20F%20%3D%20%7B%0D%0A%20%20()%3A%20string%2C%0D%0A%20%20(number)%3A%20string%2C%0D%0A%20%20(string)%3A%20string%0D%0A%7D%0D%0A%0D%0Aconst%20f%3A%20F%20%3D%20(x%3F%3A%20number%20%7C%20string)%20%3D%3E%20%7B%0D%0A%20%20return%20x%20%3F%20x.toString()%20%3A%20''%3B%0D%0A%7D%0D%0A)


```ts
type F = {
(): string,
(x: number): string,
(x: string): string
}
const f: F = (x?: number | string) => {
return x ? x.toString() : '';
}
```

Use call property to annotate function statics: [TypeScript Playground](https://www.typescriptlang.org/play/#src=type%20MemoizedFactorialType%20%3D%20%7B%0D%0A%20%20cache%3F%3A%20%7B%0D%0A%20%20%20%20%5Bn%3A%20number%5D%3A%20number%2C%0D%0A%20%20%7D%2C%0D%0A%20%20(n%3A%20number)%3A%20number%2C%0D%0A%7D%0D%0A%0D%0Aconst%20factorial%3A%20MemoizedFactorialType%20%3D%20n%20%3D%3E%20%7B%0D%0A%20%20if%20(!factorial.cache)%20%7B%0D%0A%20%20%20%20factorial.cache%20%3D%20%7B%7D%0D%0A%20%20%7D%0D%0A%20%20else%20if%20(factorial.cache%5Bn%5D%20!%3D%3D%20undefined)%20%7B%0D%0A%20%20%20%20return%20factorial.cache%5Bn%5D%0D%0A%20%20%7D%0D%0A%20%20factorial.cache%5Bn%5D%20%3D%20n%20%3D%3D%3D%200%20%3F%201%20%3A%20n%20*%20factorial(n%20-%201)%0D%0A%20%20return%20factorial.cache%5Bn%5D%0D%0A%7D)

```ts
type MemoizedFactorialType = {
cache?: {
[n: number]: number,
},
(n: number): number,
}
const factorial: MemoizedFactorialType = n => {
if (!factorial.cache) {
factorial.cache = {}
}
else if (factorial.cache[n] !== undefined) {
return factorial.cache[n]
}
factorial.cache[n] = n === 0 ? 1 : n * factorial(n - 1)
return factorial.cache[n]
}
```

Reference:
- [Callable on TypeScript Book](https://github.com/basarat/typescript-book/blob/master/docs/types/callable.md)


## optional parameters

### Flow and TypeScript
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.