Skip to content

Commit

Permalink
Fix #1
Browse files Browse the repository at this point in the history
except for 'mixed' type, needs more info
  • Loading branch information
niieani committed Dec 23, 2016
1 parent 24a3c0b commit a82484d
Showing 1 changed file with 155 additions and 50 deletions.
205 changes: 155 additions & 50 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ I'm open to contributions and comments.
| expressiveness | great (since TS @ 2.1) | great |
| type safety | great (TS @ 2.0) | great |
| typings for public libraries | plenty of well mainained typings | a handful of mostly incomplete typings |
| unique features | autocomplete for object construction, huge library of mainained Typings, `readonly` properties, `never` type, namespacing | variance, existential types `*`, testing all potential code-paths when typings not declared for maximum inference, `$Diff<A, B>` type |
| ecosystem flexibility | no extensions as of yet | no extensions as of yet |
| unique features | <ul><li>autocomplete for object construction</li><li>declarable `this` in functions (typing binding)</li><li>large library of mainained typings</li><li>more flexible type mapping via iteration</li><li>namespacing</li></ul> | <ul><li>variance</li><li>existential types `*`</li><li>testing potential code-paths when types not declared for maximum inference</li><li>`$Diff<A, B>` type</li></ul> |
| ecosystem flexibility | work in progress | no extensions |
| programmatic hooking | architecture prepared, work in progress | work in progress |

# Differences in syntax

Expand Down Expand Up @@ -122,28 +123,32 @@ declare module "*.css" {

## Exact/Partial Object Types

By default objects in Flow are not strict (exact), whereas in TypeScript they are always strict, unless set as partial.
By default objects in Flow are not exact (can contain more properties than declared), whereas in TypeScript they are always exact (must contain only declared properties).

### Flow

When using flow, `{ name: string }` only means “an object with **at least** a name property”.

```js
type StrictUser = {| name: string, age: number |};
type ExactUser = {| name: string, age: number |};
type User = { name: string, age: number };
type PartialUser = $Shape<User>;
type OptionalUser = $Shape<User>; // all properties become optional
```

### TypeScript

TypeScript is more strict here, in that if you want to use a property which is not declared, you must explicitly say so by defining the indexed property. You will be allowed to use custom properties, but will have to access them through the bracket access syntax, i.e. UserInstance['someProperty']. At the moment, you cannot define "open" (non-exact) types using TypeScript. This is mostly a design decision as it forces you to write the typings upfront.

```js
type StrictUser = { name: string, age: number };
type PartialUser = Partial<{ name: string, age: number }>;
type ExactUser = { name: string, age: number };
type User = { name: string, age: number, [otherProperty: any] };
type OptionalUser = Partial<{ name: string, age: number }>; // all properties become optional
```

### Reference

- https://flowtype.org/docs/objects.html
- https://github.com/Microsoft/TypeScript/issues/2710

## Importing types

Expand Down Expand Up @@ -194,7 +199,10 @@ var props = {
baz: 'three',
}

function getProp<T>(key: $Enum<typeof props>): T {
type PropsType = typeof props;
type KeysOfProps = $Enum<PropsType>;

function getProp<T>(key: KeysOfProps): T {
return props[key]
}
```
Expand All @@ -209,92 +217,171 @@ var props = {
}

type PropsType = typeof props
type KeysOfProps = keyof PropsType;

function getProp<K extends keyof PropsType>(key: K): PropsType[K] {
function getProp<T>(key: KeysOfProps): T {
return props[key]
}
```

## Mapped Types

TODO: use an example which does the same
## Records

### Flow

```js
type ExtractCodomain = <V>(v: () => V) => V;
function f<O>(o: O): $ObjMap<O, ExtractCodomain>;
type $Record<T, U> = {[key: $Enum<T>]: U}
type SomeRecord = $Record<{ a: number }, string>
```

### TypeScript

```ts
type Partial<T> = {
[P in keyof T]?: T[P];
};
type SomeRecord = Record<{ a: number }, string>
```
# Same syntax
## Lookup Types
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`).
### Flow
## optional parameters
```js
type A = {
thing: string
}

### Flow and TypeScript
type lookedUpThing = $PropertyType<A, 'thing'>
```
```js
function(a?: string) {}
### TypeScript
```ts
type A = {
thing: string
}

type lookedUpThing = typeof A['thing']
```
## Flow's "mixed" type
## Mapped Types / Foreach Property
Flow's `mixed` type is simply a union of all the basic types (string, number, boolean) without their Object versions.
### Flow
```js
type InputType = { hello: string };
type MappedType = $ObjMap<InputType, number>;

This comment has been minimized.

Copy link
@vkurchatkin

vkurchatkin Dec 23, 2016

This doesn't work, second parameter must be a function type, ()=>number in this example

This comment has been minimized.

Copy link
@niieani

niieani Dec 23, 2016

Author Owner

Ok, thanks @vkurchatkin. Is there any documentation anywhere on how to use this properly?

```

### TypeScript

The TypeScript equivalent should be:
A bit more flexibility here, as you have access to each individual key name and can combine with Lookup types and even do simple transformations.

```ts
type mixed = string | number | boolean
type InputType = { hello: string };
type MappedType = {
[P in keyof InputType]: number;
};
```

Reference: https://flowtype.org/docs/quick-reference.html#mixed
## Read-only Types

# TypeScript-only concepts
### Flow

## [Non-null assertion operator](https://github.com/Microsoft/TypeScript/pull/7140)
```js
type A = {
+b: string
}

Add `!` to signify we know an object is non-null.
let a: A = { b: 'something' }
a.b = 'something-else'; // ERROR
a = { b: 'something-else' } // ERROR: reassignment is NOT allowed in Flow

This comment has been minimized.

Copy link
@vkurchatkin

vkurchatkin Dec 23, 2016

reassignment is allowed

This comment has been minimized.

Copy link
@niieani

niieani Dec 23, 2016

Author Owner

So it works exactly the same as the readonly modifier in TypeScript?

```

### TypeScript

```ts
// Compiled with --strictNullChecks
function validateEntity(e: Entity?) {
// Throw exception if e is null or invalid entity
type A = {
readonly b: string
}

function processEntity(e: Entity?) {
validateEntity(e);
let s = e!.name; // Assert that e is non-null and access name
let a: A = { b: 'something' }
a.b = 'something-else'; // ERROR
a = { b: 'something-else' } // OK: reassignment is alowed in TypeScript
```

## "Impossible flow" type

### Flow

`empty`

```js
function returnsImpossible() {
throw new Error();
}

// type of returnsImpossible() is 'empty'
```

## Lookup Types
### TypeScript

`never`

```ts
type A = {
thing: string
function returnsImpossible() {
throw new Error();
}

type lookedUpThing = typeof A['thing']
// type of returnsImpossible() is 'never'
```

## Read-only Types
# Same syntax

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`).

## optional parameters

### Flow and TypeScript

```js
function(a?: string) {}
```

# TypeScript-only concepts

## Declarable arbitrary `this` in functions (outside of objects)

```ts
type A = {
readonly b: string
function something(this: { hello: string }, firstArg: string) {
return this.hello + firstArg;
}
```

let a: A = { b: 'something' }
a.b = 'something-else'; // ERROR
## Private and Public properties in classes

```ts
class SomeClass {
constructor(public prop: string, private prop2: string) {
// transpiles to:
// this.prop = prop;
// this.prop2 = prop2;
}
private prop3: string;
}
```

## [Non-null assertion operator](https://github.com/Microsoft/TypeScript/pull/7140)

Add `!` to signify we know an object is non-null.

```ts
// Compiled with --strictNullChecks
function validateEntity(e: Entity?) {
// Throw exception if e is null or invalid entity
}

function processEntity(e: Entity?) {
validateEntity(e);
let s = e!.name; // Assert that e is non-null and access name
}
```

# Flow-only concepts
Expand All @@ -306,17 +393,21 @@ type C = $Diff<{ a: string, b: number }, { a: string }>
// C is { b: number}
```

TypeScript has a proposal for this (needs link).
TypeScript has a [proposal](https://github.com/Microsoft/TypeScript/issues/12215) for an equivalent.

## `$Subtype<T>`

## Inferred generics / existential types
In TypeScript, structural types are always subtypes of themselves, so there is no need for such a concept.

This comment has been minimized.

Copy link
@vkurchatkin

vkurchatkin Dec 23, 2016

The same in Flow. To be fair, I have no idea what is the purpose of $Subtype, it's not widely used

This comment has been minimized.

Copy link
@niieani

niieani Dec 23, 2016

Author Owner

Ok, I can remove this part then.


`*` as a generic parameter tries to infer the type if possible
## Inferred existential types

`*` as a type or a generic parameter signifies to the type-checker to infer the type if possible

```js
Array<*>
```

TypeScript has a proposal for this (needs link).
TypeScript has a proposal for an equivalent (needs link).

## Variance

Expand All @@ -330,6 +421,20 @@ function getLength(o: {+p: ?string}): number {
[TypeScript proposal](https://github.com/Microsoft/TypeScript/issues/10717)
## Flow's "mixed" type
NOTE: This is probably incorrect (#1). Open to PRs with corrections.
Flow's `mixed` type is simply a union of all the basic types (string, number, boolean) without their Object versions.
The TypeScript polyfill/equivalent should be:
```ts
type mixed = string | number | boolean
```
Reference: https://flowtype.org/docs/quick-reference.html#mixed
## Useful References
* https://github.com/Microsoft/TypeScript/issues/1265
Expand Down

0 comments on commit a82484d

Please sign in to comment.