From e291c1f2bda94a7a23464441437c34b8307ea8f6 Mon Sep 17 00:00:00 2001 From: Wei Gao Date: Mon, 3 Jun 2019 10:29:54 +0800 Subject: [PATCH 1/8] Add function statics and object callable properties --- README.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/README.md b/README.md index 6b3e7db..b84df96 100644 --- a/README.md +++ b/README.md @@ -540,6 +540,36 @@ function add(x, y) { } ``` +## Function statics and object callable properties + +### Flow + +You can use objects with callable properties as function with statics. This is useful when annotating memoized functions. + +```js +type MemoizedFactorialType = { + cache: { + [number]: number, + }, + [[call]](number): number, // callable property +} + +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] +} +``` + +### TypeScript + +Not supported now, [proposal to tc39](https://github.com/microsoft/TypeScript/issues/25628). + ## Read-only Types ### Flow From 3415f907f12054c5426630f3abcd4bd38368095c Mon Sep 17 00:00:00 2001 From: Wei Gao Date: Mon, 3 Jun 2019 19:47:24 +0800 Subject: [PATCH 2/8] Update function statics and object callables - Use simpler examples - Add TypeScript on object callables --- README.md | 63 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index b84df96..e4a2e43 100644 --- a/README.md +++ b/README.md @@ -540,29 +540,61 @@ function add(x, y) { } ``` -## Function statics and object callable properties +## Object callable property ### Flow -You can use objects with callable properties as function with statics. This is useful when annotating memoized functions. +You can use objects with callable properties as functions. ```js -type MemoizedFactorialType = { - cache: { - [number]: number, - }, - [[call]](number): number, // callable property +type ReturnString = { + (): string +}; +const foo: ReturnString = () => "hello"; +const bar: string = foo(); +``` + +Multiple call properties are supported + +```js +const foo: { (): string, (x: number): string } = function(x?: number): string { + return "bar"; +}; +``` + +Reference: + +[Callable Objects](https://flow.org/en/docs/types/functions/#callable-objects-) + +### TypeScript + +```ts +interface ReturnString { + (): string; } +const foo: ReturnString = () => "hello"; +const bar: string = foo(); +``` -const factorial: MemoizedFactorialType = n => { - if (!factorial.cache) { - factorial.cache = {} - } - if (factorial.cache[n] !== undefined) { - return factorial.cache[n] + + +Reference: + +[Callable](https://github.com/basarat/typescript-book/blob/master/docs/types/callable.md) + +## Function statics + +### Flow + +Functions are also objects and you can annotate function statics. + +```js +function foo(): string { + (foo.bar: string); + if (!foo.bar) { + foo.bar = "hello"; } - factorial.cache[n] = n === 0 ? 1 : n * factorial(n - 1) - return factorial.cache[n] + return foo.bar; } ``` @@ -570,7 +602,6 @@ const factorial: MemoizedFactorialType = n => { Not supported now, [proposal to tc39](https://github.com/microsoft/TypeScript/issues/25628). -## Read-only Types ### Flow From a2208d3ee32d12ead4694113d12275a5bb447cfc Mon Sep 17 00:00:00 2001 From: Wei Gao Date: Mon, 3 Jun 2019 20:27:09 +0800 Subject: [PATCH 3/8] Add TypeScript example for overloading callable --- README.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e4a2e43..c8067e5 100644 --- a/README.md +++ b/README.md @@ -576,7 +576,18 @@ const foo: ReturnString = () => "hello"; const bar: string = foo(); ``` - +Overloading callable is supported + +```ts +interface Overloaded { + (): string; + (x: number): string; +} + +const foo: Overloaded = (x?: number) => { + return 'bar'; +} +``` Reference: From faac61fe47fd11bb01a670056f3f69789bf7d395 Mon Sep 17 00:00:00 2001 From: Wei Gao Date: Mon, 3 Jun 2019 22:50:46 +0800 Subject: [PATCH 4/8] Updates on callable properties --- README.md | 51 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index c8067e5..ae1c20d 100644 --- a/README.md +++ b/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. @@ -544,54 +546,65 @@ function add(x, y) { ### Flow -You can use objects with callable properties as functions. +You can use objects with callable properties as functions: [Try Flow](https://flow.org/try/#0PTAEAEDMBsHsHcBQiAuBPADgU1AMVALygDeiooAFAJQBcoAzigE4CWAdgOaIC+A3IgGNYbRqEh18RaoQB8oAEQALLNDjz+QkSlDLVsOo1adCY6ryA) ```js -type ReturnString = { +type F = { (): string }; -const foo: ReturnString = () => "hello"; -const bar: string = foo(); +const f: F = () => "hello"; +const hello: string = f(); ``` -Multiple call properties are supported +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 -const foo: { (): string, (x: number): string } = function(x?: number): string { - return "bar"; -}; +type F = { + (): string, + [[call]]: (number) => string, + [[call]](string): string +} + +const f: F = (x?: number | string) => { + return x ? x.toString() : ''; +} ``` Reference: -[Callable Objects](https://flow.org/en/docs/types/functions/#callable-objects-) +- [Callable Objects](https://flow.org/en/docs/types/functions/#callable-objects-) ### 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 -interface ReturnString { +type F = { (): string; } -const foo: ReturnString = () => "hello"; +const foo: F = () => "hello"; const bar: string = foo(); ``` -Overloading callable is supported +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 -interface Overloaded { - (): string; - (x: number): string; +type F = { + (): string, + (number): string, + (string): string } -const foo: Overloaded = (x?: number) => { - return 'bar'; +const f: F = (x?: number | string) => { + return x ? x.toString() : ''; } ``` Reference: - -[Callable](https://github.com/basarat/typescript-book/blob/master/docs/types/callable.md) +- [Callable on TypeScript Book](https://github.com/basarat/typescript-book/blob/master/docs/types/callable.md) ## Function statics From e103e1f4f34cc65cc24127c66c4f0af3b7a8b7f2 Mon Sep 17 00:00:00 2001 From: Wei Gao Date: Mon, 3 Jun 2019 23:31:02 +0800 Subject: [PATCH 5/8] Updates on callable properties - Move to "same syntax" - Add a few library definitions as reference --- README.md | 133 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 70 insertions(+), 63 deletions(-) diff --git a/README.md b/README.md index ae1c20d..37eceba 100644 --- a/README.md +++ b/README.md @@ -542,69 +542,6 @@ function add(x, y) { } ``` -## Object callable property - -### 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() : ''; -} -``` - -Reference: - -- [Callable Objects](https://flow.org/en/docs/types/functions/#callable-objects-) - -### 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, - (number): string, - (string): string -} - -const f: F = (x?: number | string) => { - return x ? x.toString() : ''; -} -``` - -Reference: -- [Callable on TypeScript Book](https://github.com/basarat/typescript-book/blob/master/docs/types/callable.md) ## Function statics @@ -720,6 +657,76 @@ 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. + +### 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() : ''; +} +``` + +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, + (number): string, + (string): string +} + +const f: F = (x?: number | string) => { + return x ? x.toString() : ''; +} +``` + +Reference: +- [Callable on TypeScript Book](https://github.com/basarat/typescript-book/blob/master/docs/types/callable.md) + + ## optional parameters ### Flow and TypeScript From 82f1b99afff9fbcd82aad503086cabe8be6186aa Mon Sep 17 00:00:00 2001 From: Wei Gao Date: Mon, 3 Jun 2019 23:35:07 +0800 Subject: [PATCH 6/8] Add back the line # Read-only Types that got deleted by accident --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 37eceba..e8a9325 100644 --- a/README.md +++ b/README.md @@ -563,6 +563,7 @@ function foo(): string { Not supported now, [proposal to tc39](https://github.com/microsoft/TypeScript/issues/25628). +## Read-only Types ### Flow From 148fccb56b457d4a94920dbb3216730bc847e2ed Mon Sep 17 00:00:00 2001 From: Wei Gao Date: Tue, 4 Jun 2019 01:02:37 +0800 Subject: [PATCH 7/8] Not sure how TS supports function statics --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e8a9325..8afdade 100644 --- a/README.md +++ b/README.md @@ -561,7 +561,7 @@ function foo(): string { ### TypeScript -Not supported now, [proposal to tc39](https://github.com/microsoft/TypeScript/issues/25628). + ## Read-only Types From 6cc77ba124c3e309186d2d3a50b1f5621e3b9253 Mon Sep 17 00:00:00 2001 From: Wei Gao Date: Tue, 4 Jun 2019 23:07:44 +0800 Subject: [PATCH 8/8] Resolve PR discussion and add function statics --- README.md | 71 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 8afdade..638d401 100644 --- a/README.md +++ b/README.md @@ -542,27 +542,6 @@ function add(x, y) { } ``` - -## Function statics - -### Flow - -Functions are also objects and you can annotate function statics. - -```js -function foo(): string { - (foo.bar: string); - if (!foo.bar) { - foo.bar = "hello"; - } - return foo.bar; -} -``` - -### TypeScript - - - ## Read-only Types ### Flow @@ -662,6 +641,8 @@ Most of the syntax of Flow and TypeScript is the same. TypeScript is more expres 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) @@ -689,6 +670,28 @@ const f: F = (x?: number | string) => { } ``` +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-) @@ -715,8 +718,8 @@ This is also supported by TypeScript: [TypeScript Playground](https://www.typesc ```ts type F = { (): string, - (number): string, - (string): string + (x: number): string, + (x: string): string } const f: F = (x?: number | string) => { @@ -724,6 +727,28 @@ const f: F = (x?: number | string) => { } ``` +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)