In this docuemnt
- Other documents
- Pre-installation
- Editor helpers
- Quick start
- Differences
- Types
- Types vs Interfaces
- Type and Interface prefix
- Gotchas
- General - Contains general philosophy and overview of this package
- Modules docs - Contains implementation guides (i.e., adding types, use observer, etc.)
- node
- npm
- Prettier setup in your editor https://prettier.io/
- Stylelint setup in your editor https://stylelint.io/
- Eslint setup in your editor https://eslint.org/
-
Install your dependencies:
npm run bootstrap
-
To build publish file:
npm run build:publish appstore
-
Libary usage:
import React from 'react' import Appstore from '@deriv/appstore'; const Component = ({client, ServerTIme, ui, WS, config}) => { return <Appstore client={client} server_time={ServerTime} ui={ui} ws={WS} config={config} />; } };
-
File Structure
src
├── assets/
│ ├── images/
├── components/
│ ├── ...
├── constants/
│ ├── ...
├── stores/
│ ├── ...
├── types/
│ ├── ...
├── index.js
index.js // publish file
webpack.config.js
package.json
Defining components in TypeScript is not very different from doing so in JavaScript, but the first thing you'll notice is that we now no longer have any PropTypes and there are a bunch of new keywords added. Take the example below on how to define a component:
const App ({ counter, name }) => {
return (
<div>{ name } clicked { counter } times.</div>
)
}
App.propTypes = {
counter: PropTypes.number.isRequired,
name: PropTypes.string.isRequired,
}
const App: React.FC<TAppProps> ({ counter, name }) => {
return (
<div>{ name } clicked { counter } times.</div>
)
}
type TAppProps = {
counter: number;
name: string;
}
As you can see, TypeScript is a lot more explicit and we have to state the type of variable that App
is (React.FC
with its contents being in the shape of TAppProps
). You can compare it to PropTypes, but it's a lot stricter and will throw compilation errors if the shapes don't match.
In most cases types will be defined within the same component, however, when a type should be shared across multiple files, you may put it in the src/types
folder. In this folder we have 3 named folders:
params.types.ts
: Contains shared types for function parametersprops.types.ts
: Contains shared types for component propsstores.types.ts
: Contains types for the app's stores
In general, try to append any new types to these files before creating a new *.types.ts
file here.
With the latest typescript version, functionalities and capabilities of both types and interfaces become more similar. Hence for appstore project, here are the cases when to use types or interfaces
Do use types to typecheck react proptypes object
const About: React.FC<TAbout> = ({ title, description }) => {
...
};
type TAbout = {
title: string;
description: number;
};
Do use types to typecheck a function. Aside from the similar ability, it possesses with the interface, you can use types to type-check the argument and the return type of a function.
type TStatusShape = {
countries: string[], // an array of strings
status: string
};
type TWebsiteStatus = (
website_status: TStatusShape
) => Person;
const isEu: TWebsiteStatus = (website_status) => {
...
return is_eu;
};
--TODO add cases when to use interfaces--
// noop
The name shape of type/interface prefixed with T
for type and I
for Interface that is used for react props. The idea is to differentiate the component name and the type name, as for the other used for type, it might not necessarily need to be prefixed.
type MarketType = {
icon: string;
title: string;
};
type TInstruments = {
title: string;
active_symbols: MarketType[];
};
In @deriv/appstore we no longer use a connect
function to inject props into our components, instead, we use hooks for everything (useStores
). In addition, if you're rendering observables you will have to wrap your component in an observer
call imported from mobx-react-lite
to ensure the stores and UI are synchronised (i.e. it will re-render when an observable change).
A couple of things to remember:
Wrap at the export level, not at the component definition level:
const MyComponent: React.FC = () => {
const { my_store } = useStores();
return <div>{ my_store.my_observable_value }</div>
}
export default observer(MyComponent);
const MyComponent: React.FC = observer(() => {
const { my_store } = useStores();
return <div>{ my_store.my_observable_value }</div>
});
export default MyComponent;
Also, make sure to keep the observer
wrapper as close to the component as possible. For example, if you're using withRouter
wrapper from react-router-dom
:
import { withRouter } from 'react-router-dom';
import { observer } from 'mobx-react-lite';
const MyComponent: React.FC = () => {
const { my_store } = useStores();
return <div>{ my_store.my_observable_value }</div>
};
export default withRouter(observer(MyComponent));
import { withRouter } from 'react-router-dom';
import { observer } from 'mobx-react-lite';
const MyComponent: React.FC = () => {
const { my_store } = useStores();
return <div>{ my_store.my_observable_value }</div>
};
export default observer(withRouter(MyComponent));