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

[docs]: Documentation for Class<T>, $PropertyType<T, x>, $Exact<T>, and * #2983

Closed
wants to merge 2 commits into from
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 133 additions & 7 deletions website/docs/ref/utility-types.doc.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@ next: react.html
---
*/

/*
# Utility Types
*/

/*
## `$Keys<T>`
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was duplicated; the header is already present from the title on L5

In Flow you can [use union types similar to enums](builtins.html#literal-types):
Expand Down Expand Up @@ -91,8 +87,41 @@ As you may have noticed, the example is not a random one. `$Diff` is exactly wha

/*
## `Class<T>`
Work in progress
Given a type `T` representing instances of a class `C`, the type `Class<T>` is the type of the class `C`.
For example:
*/

class Store {}
class ExtendedStore extends Store {}
class Model {}

function makeStore(storeClass: Class<Store>) {
return new storeClass();
}

(makeStore(Store): Store);
(makeStore(ExtendedStore): Store);
// $ExpectError
(makeStore(Model): Model); // error, Class<Model> does not satisfy Class<Store>
// $ExpectError
(makeStore(ExtendedStore): Model); // Flow infers the return type

/*
For classes that take type parameters, you must also provide the parameter. For example:
*/

class ParamStore<T: *> {
constructor(data: T) {}
}

function makeParamStore<T>(storeClass: Class<ParamStore<T>>, data: T): ParamStore<T> {
return new storeClass(data);
}
(makeParamStore(ParamStore, 1): ParamStore<number>);
// $ExpectError
(makeParamStore(ParamStore, 1): ParamStore<boolean>);

/*
## `$Supertype<T>`
Work in progress

Expand All @@ -102,6 +131,103 @@ Work in progress
## `$Abstract<T>`
Work in progress

## `#PropertyType<T, x>`
Work in progress
## `$PropertyType<T, x>`
A $PropertyType is the type at a given key.

As of Flow v0.36.0, `x` must be a literal string. In future versions, `x` may be allowed to be any type, as long
as that type exists on the keys of `T`.
*/

type Person = {
name: string,
age: number,
parent: Person
};

const newName: $PropertyType<Person, 'name'> = 'Charlie';
const newAge: $PropertyType<Person, 'age'> = 21;
// $ExpectError
const newParent: $PropertyType<Person, 'parent'> = 'Mike';

/*
This can be especially useful for referring to the type of React props, or, even the entire `props` type itself.
*/

import React from 'react';
class Tooltip extends React.Component {
props: {
text: string,
onMouseOver: ({x: number, y: number}) => void
};
}

const someProps: $PropertyType<Tooltip, 'props'> = {
text: 'foo',
onMouseOver: (data: {x: number, y: number}) => undefined
};

// $ExpectError
const otherProps: $PropertyType<Tooltip, 'props'> = {
text: 'foo'
};

/*
You can even nest lookups:
*/
type PositionHandler = $PropertyType<$PropertyType<Tooltip, 'props'>, 'onMouseOver'>;
const handler: PositionHandler = (data: {x: number, y: number}) => undefined;
// $ExpectError
const handler2: PositionHandler = (data: string) => undefined;

/*
You can use this in combination with `Class<T>` to get static props:
*/

class BackboneModel {
static idAttribute: string | false;
}

type ID = $PropertyType<Class<BackboneModel>, 'idAttribute'>;
const someID: ID = '1234';
// $ExpectError
const someBadID: ID = true;

/*
## `*`
`*` is known as the existential type.

An existential type is used as a placeholder to tell Flow to infer the type.

For example, in the `Class<ParamStore<T>>` example, we could have used an existential type for the return:
*/
function makeParamStore<T>(storeClass: Class<ParamStore<T>>, data: T): * {
return new storeClass(data);
}
(makeParamStore(ParamStore, 1): ParamStore<number>);
// $ExpectError
(makeParamStore(ParamStore, 1): ParamStore<boolean>);

/*
The `*` can be thought of as an "auto" instruction to Flow, telling it to fill in the type from context.

In comparison to `any`, `*` may allow you to avoid losing type safety.

The existential operator is also useful for automatically filling in types without unnecessary verbosity:
*/

class DataStore {
data: *; // If this weren't defined, you'd get an error just trying to assign `data`
constructor() {
this.data = {
name: 'DataStore',
isOffline: true
};
}
goOnline() {
this.data.isOffline = false;
}
changeName() {
// $ExpectError
this.data.isOffline = 'SomeStore'; // oops, wrong key!
}
}