Add T prefix for all type defs

This commit is contained in:
Jerko Steiner 2019-04-02 16:22:38 +08:00
parent db96b95522
commit 264f5aba60
69 changed files with 240 additions and 242 deletions

View File

@ -1,6 +0,0 @@
import {IAction} from './IAction'
export type GetAction<MyTypes, T extends string> =
MyTypes extends IAction<infer U, T>
? MyTypes
: never

View File

@ -1,6 +0,0 @@
import {IAsyncAction} from './IAsyncAction'
export type GetPendingAction<MyTypes, T extends string> =
MyTypes extends IAsyncAction<infer U, T> & {status: 'pending'}
? MyTypes
: never

View File

@ -1,6 +0,0 @@
import {IAsyncAction} from './IAsyncAction'
export type GetResolvedAction<MyTypes, T extends string> =
MyTypes extends IAsyncAction<infer U, T> & {status: 'resolved'}
? MyTypes
: never

View File

@ -2,9 +2,9 @@ import {IPendingAction} from './IPendingAction'
import {IResolvedAction} from './IResolvedAction'
import {IRejectedAction} from './IRejectedAction'
export type IAsyncStatus = 'pending' | 'resolved' | 'rejected'
export type TAsyncStatus = 'pending' | 'resolved' | 'rejected'
export type IAsyncAction<T, ActionType extends string> =
export type TAsyncAction<T, ActionType extends string> =
IPendingAction<T, ActionType>
| IResolvedAction<T, ActionType>
| IRejectedAction<ActionType>

View File

@ -0,0 +1,6 @@
import {IAction} from './IAction'
export type TGetAction<ActionTypes, T extends string> =
ActionTypes extends IAction<infer U, T>
? ActionTypes
: never

View File

@ -0,0 +1,6 @@
import {TAsyncAction} from './TAsyncAction'
export type TGetPendingAction<MyTypes, T extends string> =
MyTypes extends TAsyncAction<infer U, T> & {status: 'pending'}
? MyTypes
: never

View File

@ -0,0 +1,6 @@
import {TAsyncAction} from './TAsyncAction'
export type TGetResolvedAction<MyTypes, T extends string> =
MyTypes extends TAsyncAction<infer U, T> & {status: 'resolved'}
? MyTypes
: never

View File

@ -1,9 +1,9 @@
export * from './GetAction'
export * from './GetResolvedAction'
export * from './GetPendingAction'
export * from './IAction'
export * from './IAsyncAction'
export * from './IPendingAction'
export * from './IRejectedAction'
export * from './IResolvedAction'
export * from './PendingAction'
export * from './TAsyncAction'
export * from './TGetAction'
export * from './TGetPendingAction'
export * from './TGetResolvedAction'

View File

@ -1,9 +1,9 @@
import {createCRUDActions} from './CRUDActions'
import React from 'react'
import {AnyAction} from 'redux'
import {CRUDReducer, ICRUDMethod} from './'
import {CRUDReducer, TCRUDMethod} from './'
import {HTTPClientMock, TestUtils, getError} from '../test-utils'
import {IMethod} from '@rondo/common'
import {TMethod} from '@rondo/common'
import {IPendingAction} from '../actions'
describe('CRUD', () => {
@ -100,7 +100,7 @@ describe('CRUD', () => {
})
function dispatch(
method: ICRUDMethod,
method: TCRUDMethod,
action: IPendingAction<unknown, string>,
) {
store.dispatch(action)
@ -109,13 +109,13 @@ describe('CRUD', () => {
return action
}
function getUrl(method: ICRUDMethod) {
function getUrl(method: TCRUDMethod) {
return method === 'save' || method === 'findMany'
? '/one/1/two'
: '/one/1/two/2'
}
function getHTTPMethod(method: ICRUDMethod): IMethod {
function getHTTPMethod(method: TCRUDMethod): TMethod {
switch (method) {
case 'save':
return 'post'
@ -131,7 +131,7 @@ describe('CRUD', () => {
describe('Promise rejections', () => {
const testCases: Array<{
method: ICRUDMethod
method: TCRUDMethod
params: any
}> = [{
method: 'findOne',
@ -203,7 +203,7 @@ describe('CRUD', () => {
const entity = {id: 100, name: 'test'}
const testCases: Array<{
method: ICRUDMethod
method: TCRUDMethod
params: any
body?: any
response: any

View File

@ -1,12 +1,10 @@
import {ICRUDAction} from './ICRUDAction'
import {ICRUDMethod} from './ICRUDMethod'
import {TCRUDAction} from './TCRUDAction'
import {TCRUDMethod} from './TCRUDMethod'
import {IHTTPClient, ITypedRequestParams} from '../http'
import {IRoutes, Filter, OnlyDefined} from '@rondo/common'
import {IRoutes, TFilter, TOnlyDefined} from '@rondo/common'
export type Optional<T> = T extends {} ? T : undefined
type Action<T, ActionType extends string, Method extends ICRUDMethod> =
Filter<ICRUDAction<T, ActionType>, {method: Method, status: 'pending'}>
type TAction<T, ActionType extends string, Method extends TCRUDMethod> =
TFilter<TCRUDAction<T, ActionType>, {method: Method, status: 'pending'}>
export class SaveActionCreator<
T extends IRoutes,
@ -20,10 +18,10 @@ export class SaveActionCreator<
readonly type: ActionType,
) {}
save = (params: OnlyDefined<{
save = (params: TOnlyDefined<{
body: T[Route]['post']['body'],
params: T[Route]['post']['params'],
}>): Action<T[Route]['post']['response'], ActionType, 'save'> => {
}>): TAction<T[Route]['post']['response'], ActionType, 'save'> => {
const p = params as any
return {
payload: this.http.post(this.route, p.body, p.params),
@ -46,10 +44,10 @@ export class FindOneActionCreator<
readonly type: ActionType,
) {}
findOne = (params: OnlyDefined<{
query: Optional<T[Route]['get']['query']>,
findOne = (params: TOnlyDefined<{
query: T[Route]['get']['query'],
params: T[Route]['get']['params'],
}>): Action<T[Route]['get']['response'], ActionType, 'findOne'> => {
}>): TAction<T[Route]['get']['response'], ActionType, 'findOne'> => {
const p = params as any
return {
payload: this.http.get(this.route, p.query, p.params),
@ -73,10 +71,10 @@ export class UpdateActionCreator<
readonly type: ActionType,
) {}
update = (params: OnlyDefined<{
update = (params: TOnlyDefined<{
body: T[Route]['put']['body'],
params: T[Route]['put']['params'],
}>): Action<T[Route]['put']['response'], ActionType, 'update'> => {
}>): TAction<T[Route]['put']['response'], ActionType, 'update'> => {
const p = params as any
return {
payload: this.http.put(this.route, p.body, p.params),
@ -100,10 +98,10 @@ export class RemoveActionCreator<
readonly type: ActionType,
) {}
remove = (params: OnlyDefined<{
body: Optional<T[Route]['delete']['body']>,
remove = (params: TOnlyDefined<{
body: T[Route]['delete']['body'],
params: T[Route]['delete']['params'],
}>): Action<T[Route]['delete']['response'], ActionType, 'remove'> => {
}>): TAction<T[Route]['delete']['response'], ActionType, 'remove'> => {
const p = params as any
return {
payload: this.http.delete(this.route, p.body, p.params),
@ -126,8 +124,8 @@ export class FindManyActionCreator<
readonly type: ActionType,
) {}
findMany = (params: OnlyDefined<{
query: Optional<T[Route]['get']['query']>,
findMany = (params: TOnlyDefined<{
query: T[Route]['get']['query'],
params: T[Route]['get']['params'],
}>): {
payload: Promise<T[Route]['get']['response']>

View File

@ -1,7 +1,7 @@
import {IAction, IResolvedAction} from '../actions'
import {ICRUDAction} from './ICRUDAction'
import {ICRUDMethod} from './ICRUDMethod'
import {indexBy, without, Filter} from '@rondo/common'
import {TCRUDAction} from './TCRUDAction'
import {TCRUDMethod} from './TCRUDMethod'
import {indexBy, without, TFilter} from '@rondo/common'
export interface ICRUDEntity {
readonly id: number
@ -65,7 +65,7 @@ export class CRUDReducer<
handleRejected = (
state: ICRUDState<T>,
method: ICRUDMethod,
method: TCRUDMethod,
error: Error,
): ICRUDState<T> => {
return {
@ -82,7 +82,7 @@ export class CRUDReducer<
handleLoading = (
state: ICRUDState<T>,
method: ICRUDMethod,
method: TCRUDMethod,
): ICRUDState<T> => {
return {
...state,
@ -163,7 +163,7 @@ export class CRUDReducer<
reduce = (
state: ICRUDState<T> | undefined,
action: ICRUDAction<T, ActionType>,
action: TCRUDAction<T, ActionType>,
): ICRUDState<T> => {
const {defaultState} = this
state = state || defaultState

View File

@ -1,24 +0,0 @@
import {IAsyncAction} from '../actions'
import {ICRUDMethod} from './ICRUDMethod'
export type ICRUDSaveAction<T, ActionType extends string> =
IAsyncAction<T, ActionType> & {method: Extract<ICRUDMethod, 'save'>}
export type ICRUDUpdateAction<T, ActionType extends string> =
IAsyncAction<T, ActionType> & {method: Extract<ICRUDMethod, 'update'>}
export type ICRUDRemoveAction<T, ActionType extends string> =
IAsyncAction<T, ActionType> & {method: Extract<ICRUDMethod, 'remove'>}
export type ICRUDFindOneAction<T, ActionType extends string> =
IAsyncAction<T, ActionType> & {method: Extract<ICRUDMethod, 'findOne'>}
export type ICRUDFindManyAction<T, ActionType extends string> =
IAsyncAction<T[], ActionType> & {method: Extract<ICRUDMethod, 'findMany'>}
export type ICRUDAction<T, ActionType extends string> =
ICRUDSaveAction<T, ActionType>
| ICRUDUpdateAction<T, ActionType>
| ICRUDRemoveAction<T, ActionType>
| ICRUDFindOneAction<T, ActionType>
| ICRUDFindManyAction<T, ActionType>

View File

@ -1 +0,0 @@
export type ICRUDMethod = 'save' | 'update' | 'findOne' | 'findMany' | 'remove'

View File

@ -0,0 +1,24 @@
import {TAsyncAction} from '../actions'
import {TCRUDMethod} from './TCRUDMethod'
export type TCRUDSaveAction<T, ActionType extends string> =
TAsyncAction<T, ActionType> & {method: Extract<TCRUDMethod, 'save'>}
export type TCRUDUpdateAction<T, ActionType extends string> =
TAsyncAction<T, ActionType> & {method: Extract<TCRUDMethod, 'update'>}
export type TCRUDRemoveAction<T, ActionType extends string> =
TAsyncAction<T, ActionType> & {method: Extract<TCRUDMethod, 'remove'>}
export type TCRUDFindOneAction<T, ActionType extends string> =
TAsyncAction<T, ActionType> & {method: Extract<TCRUDMethod, 'findOne'>}
export type TCRUDFindManyAction<T, ActionType extends string> =
TAsyncAction<T[], ActionType> & {method: Extract<TCRUDMethod, 'findMany'>}
export type TCRUDAction<T, ActionType extends string> =
TCRUDSaveAction<T, ActionType>
| TCRUDUpdateAction<T, ActionType>
| TCRUDRemoveAction<T, ActionType>
| TCRUDFindOneAction<T, ActionType>
| TCRUDFindManyAction<T, ActionType>

View File

@ -0,0 +1 @@
export type TCRUDMethod = 'save' | 'update' | 'findOne' | 'findMany' | 'remove'

View File

@ -1,4 +1,4 @@
export * from './CRUDActions'
export * from './CRUDReducer'
export * from './ICRUDAction'
export * from './ICRUDMethod'
export * from './TCRUDAction'
export * from './TCRUDMethod'

View File

@ -1,4 +1,4 @@
import {GetAction, IAction} from '../actions'
import {TGetAction, IAction} from '../actions'
export interface ICrumbLink {
name: string
@ -10,10 +10,10 @@ export interface ICrumbs {
current: string
}
export type CrumbsActionType =
export type TCrumbsAction =
IAction<ICrumbs, 'BREADCRUMBS_SET'>
type Action<T extends string> = GetAction<CrumbsActionType, T>
type Action<T extends string> = TGetAction<TCrumbsAction, T>
export class CrumbsActions {
setCrumbs(breadcrumbs: ICrumbs): Action<'BREADCRUMBS_SET'> {

View File

@ -1,12 +1,12 @@
import {Crumb} from './Crumb'
import {Connector, IStateSelector} from '../redux'
import {Connector, TStateSelector} from '../redux'
import {ICrumbsState} from './CrumbsReducer'
import {CrumbsActions} from './CrumbsActions'
export class CrumbsConnector extends Connector<ICrumbsState> {
protected readonly breadcrumbsActions = new CrumbsActions()
connect<State>(getLocalState: IStateSelector<State, ICrumbsState>) {
connect<State>(getLocalState: TStateSelector<State, ICrumbsState>) {
return this.wrap(
getLocalState,
state => state,

View File

@ -1,4 +1,4 @@
import {ICrumbs, CrumbsActionType} from './CrumbsActions'
import {ICrumbs, TCrumbsAction} from './CrumbsActions'
export interface ICrumbsState extends ICrumbs {
}
@ -8,7 +8,7 @@ const defaultState: ICrumbsState = {
current: 'Home',
}
export function Crumbs(state = defaultState, action: CrumbsActionType)
export function Crumbs(state = defaultState, action: TCrumbsAction)
: ICrumbsState {
switch (action.type) {
case 'BREADCRUMBS_SET':

View File

@ -1,7 +1,7 @@
import axios from 'axios'
import {IHTTPClient} from './IHTTPClient'
import {IHeader} from './IHeader'
import {IMethod, IRoutes, URLFormatter} from '@rondo/common'
import {TMethod, IRoutes, URLFormatter} from '@rondo/common'
import {IRequest} from './IRequest'
import {IResponse} from './IResponse'
import {ITypedRequestParams} from './ITypedRequestParams'
@ -31,7 +31,7 @@ export class HTTPClient<T extends IRoutes> implements IHTTPClient<T> {
async request<
P extends keyof T & string,
M extends IMethod,
M extends TMethod,
>(params: ITypedRequestParams<T, P, M>): Promise<T[P][M]['response']> {
const url = this.formatter.format(params.path, params.params)

View File

@ -1,10 +1,10 @@
import {IMethod, IRoutes} from '@rondo/common'
import {TMethod, IRoutes} from '@rondo/common'
import {ITypedRequestParams} from './ITypedRequestParams'
export interface IHTTPClient<T extends IRoutes> {
request<
P extends keyof T & string,
M extends IMethod,
M extends TMethod,
>(params: ITypedRequestParams<T, P, M>): Promise<T[P][M]['response']>
get<P extends keyof T & string>(

View File

@ -1,7 +1,7 @@
import {IMethod} from '@rondo/common'
import {TMethod} from '@rondo/common'
export interface IRequest {
method: IMethod,
method: TMethod,
url: string,
params?: {[key: string]: any},
data?: any,

View File

@ -1,9 +1,9 @@
import {IRoutes, IMethod} from '@rondo/common'
import {IRoutes, TMethod} from '@rondo/common'
export interface ITypedRequestParams<
T extends IRoutes,
P extends keyof T & string,
M extends IMethod,
M extends TMethod,
> {
method: M,
path: P,

View File

@ -1,14 +1,14 @@
import {GetAction, IAsyncAction, IAction, PendingAction} from '../actions'
import {TGetAction, TAsyncAction, IAction, PendingAction} from '../actions'
import {IAPIDef, ICredentials, INewUser, IUser} from '@rondo/common'
import {IHTTPClient} from '../http/IHTTPClient'
export type LoginActionType =
IAsyncAction<IUser, 'LOGIN'>
| IAsyncAction<unknown, 'LOGIN_LOGOUT'>
| IAsyncAction<IUser, 'LOGIN_REGISTER'>
export type TLoginAction =
TAsyncAction<IUser, 'LOGIN'>
| TAsyncAction<unknown, 'LOGIN_LOGOUT'>
| TAsyncAction<IUser, 'LOGIN_REGISTER'>
| IAction<{redirectTo: string}, 'LOGIN_REDIRECT_SET'>
type Action<T extends string> = GetAction<LoginActionType, T>
type TAction<T extends string> = TGetAction<TLoginAction, T>
export class LoginActions {
constructor(protected readonly http: IHTTPClient<IAPIDef>) {}
@ -34,7 +34,7 @@ export class LoginActions {
)
}
setRedirectTo = (redirectTo: string): Action<'LOGIN_REDIRECT_SET'> => {
setRedirectTo = (redirectTo: string): TAction<'LOGIN_REDIRECT_SET'> => {
return {
payload: {redirectTo},
type: 'LOGIN_REDIRECT_SET',

View File

@ -1,7 +1,7 @@
import {Connector} from '../redux/Connector'
import {ICredentials} from '@rondo/common'
import {ILoginState} from './LoginReducer'
import {IStateSelector} from '../redux'
import {TStateSelector} from '../redux'
import {LoginActions} from './LoginActions'
import {LoginForm} from './LoginForm'
import {bindActionCreators} from 'redux'
@ -18,7 +18,7 @@ export class LoginConnector extends Connector<ILoginState> {
super()
}
connect<State>(getLocalState: IStateSelector<State, ILoginState>) {
connect<State>(getLocalState: TStateSelector<State, ILoginState>) {
return this.wrap(
getLocalState,
state => ({

View File

@ -1,5 +1,5 @@
import {IUser} from '@rondo/common'
import {LoginActionType} from './LoginActions'
import {TLoginAction} from './LoginActions'
export interface ILoginState {
readonly error: string
@ -17,7 +17,7 @@ const defaultState: ILoginState = {
export function Login(
state = defaultState,
action: LoginActionType,
action: TLoginAction,
): ILoginState {
switch (action.type) {
// sync actions

View File

@ -1,7 +1,7 @@
import {Connector} from '../redux/Connector'
import {INewUser} from '@rondo/common'
import {ILoginState} from './LoginReducer'
import {IStateSelector} from '../redux'
import {TStateSelector} from '../redux'
import {LoginActions} from './LoginActions'
import {RegisterForm} from './RegisterForm'
import {bindActionCreators} from 'redux'
@ -20,7 +20,7 @@ export class RegisterConnector extends Connector<ILoginState> {
super()
}
connect<State>(getLocalState: IStateSelector<State, ILoginState>) {
connect<State>(getLocalState: TStateSelector<State, ILoginState>) {
return this.wrap(
getLocalState,
state => ({

View File

@ -1,4 +1,4 @@
import {IStateSelector} from './IStateSelector'
import {TStateSelector} from './TStateSelector'
import {connect, Omit} from 'react-redux'
import {Dispatch} from 'redux'
import {ComponentType} from 'react'
@ -30,7 +30,7 @@ export abstract class Connector<LocalState> {
* https://stackoverflow.com/questions/54277411
*/
abstract connect<State>(
selectState: IStateSelector<State, LocalState>,
selectState: TStateSelector<State, LocalState>,
): ComponentType<any>
protected wrap<
@ -39,7 +39,7 @@ export abstract class Connector<LocalState> {
StateProps extends Partial<Props>,
DispatchProps extends Partial<Props>,
>(
getLocalState: IStateSelector<State, LocalState>,
getLocalState: TStateSelector<State, LocalState>,
mapStateToProps: (state: LocalState) => StateProps,
mapDispatchToProps: (dispatch: Dispatch) => DispatchProps,
Component: React.ComponentType<Props>,

View File

@ -1,5 +1,5 @@
/*
* Select and return a part of the state
*/
export type IStateSelector<GlobalState, StateSlice>
export type TStateSelector<GlobalState, StateSlice>
= (state: GlobalState) => StateSlice

View File

@ -1,2 +1,2 @@
export * from './Connector'
export * from './IStateSelector'
export * from './TStateSelector'

View File

@ -3,13 +3,13 @@ import ReactDOM from 'react-dom'
import {Action} from 'redux'
import {IClientConfig} from './IClientConfig'
import {IRenderer} from './IRenderer'
import {IStoreFactory} from './IStoreFactory'
import {TStoreFactory} from './TStoreFactory'
import {Provider} from 'react-redux'
import {Router} from 'react-router-dom'
import {createBrowserHistory} from 'history'
export interface IClientRendererParams<State, A extends Action> {
readonly createStore: IStoreFactory<State, A | any>,
readonly createStore: TStoreFactory<State, A | any>,
readonly RootComponent: React.ComponentType<{config: IClientConfig}>,
readonly target?: HTMLElement
}

View File

@ -2,7 +2,7 @@ import React from 'react'
import {Action} from 'redux'
import {IClientConfig} from './IClientConfig'
import {IRenderer} from './IRenderer'
import {IStoreFactory} from './IStoreFactory'
import {TStoreFactory} from './TStoreFactory'
import {Provider} from 'react-redux'
import {StaticRouterContext} from 'react-router'
import {StaticRouter} from 'react-router-dom'
@ -10,7 +10,7 @@ import {renderToNodeStream} from 'react-dom/server'
export class ServerRenderer<State, A extends Action> implements IRenderer {
constructor(
readonly createStore: IStoreFactory<State, A | any>,
readonly createStore: TStoreFactory<State, A | any>,
readonly RootComponent: React.ComponentType<{config: IClientConfig}>,
) {}
render(url: string, config: IClientConfig, state?: any) {

View File

@ -1,5 +1,5 @@
import {Action, Store} from 'redux'
// TODO maybe Store should also be typed
export type IStoreFactory<State, A extends Action> =
export type TStoreFactory<State, A extends Action> =
(state?: State) => Store<State, A | any>

View File

@ -1,5 +1,5 @@
export * from './ClientRenderer'
export * from './IClientConfig'
export * from './IRenderer'
export * from './IStoreFactory'
export * from './TStoreFactory'
export * from './isClientSide'

View File

@ -1,19 +1,19 @@
import {IAPIDef} from '@rondo/common'
import {GetPendingAction, IAsyncAction, PendingAction} from '../actions'
import {TGetPendingAction, TAsyncAction, PendingAction} from '../actions'
import {IHTTPClient} from '../http/IHTTPClient'
import {ITeam, IUser, IUserInTeam} from '@rondo/common'
export type TeamActionType =
IAsyncAction<ITeam[], 'TEAMS'>
| IAsyncAction<ITeam, 'TEAM_CREATE'>
| IAsyncAction<ITeam, 'TEAM_UPDATE'>
| IAsyncAction<{id: number}, 'TEAM_REMOVE'>
| IAsyncAction<IUserInTeam, 'TEAM_USER_ADD'>
| IAsyncAction<{userId: number, teamId: number}, 'TEAM_USER_REMOVE'>
| IAsyncAction<{teamId: number, usersInTeam: IUserInTeam[]}, 'TEAM_USERS'>
| IAsyncAction<IUser | undefined, 'TEAM_USER_FIND'>
export type TTeamAction =
TAsyncAction<ITeam[], 'TEAMS'>
| TAsyncAction<ITeam, 'TEAM_CREATE'>
| TAsyncAction<ITeam, 'TEAM_UPDATE'>
| TAsyncAction<{id: number}, 'TEAM_REMOVE'>
| TAsyncAction<IUserInTeam, 'TEAM_USER_ADD'>
| TAsyncAction<{userId: number, teamId: number}, 'TEAM_USER_REMOVE'>
| TAsyncAction<{teamId: number, usersInTeam: IUserInTeam[]}, 'TEAM_USERS'>
| TAsyncAction<IUser | undefined, 'TEAM_USER_FIND'>
type Action<T extends string> = GetPendingAction<TeamActionType, T>
type Action<T extends string> = TGetPendingAction<TTeamAction, T>
export class TeamActions {
constructor(protected readonly http: IHTTPClient<IAPIDef>) {}

View File

@ -1,5 +1,5 @@
import {Connector} from '../redux/Connector'
import {IStateSelector} from '../redux'
import {TStateSelector} from '../redux'
import {ITeamState} from './TeamReducer'
import {TeamActions} from './TeamActions'
import {TeamManager} from './TeamManager'
@ -11,7 +11,7 @@ export class TeamConnector extends Connector<ITeamState> {
super()
}
connect<State>(getLocalState: IStateSelector<State, ITeamState>) {
connect<State>(getLocalState: TStateSelector<State, ITeamState>) {
const Component = this.wrap(
getLocalState,
state => ({

View File

@ -4,7 +4,7 @@ import {ITeam} from '@rondo/common'
import {TeamActions} from './TeamActions'
import {FaPlusSquare, FaCheck, FaEdit} from 'react-icons/fa'
export type ITeamEditorProps = {
export type TTeamEditorProps = {
type: 'add'
onAddTeam: TeamActions['createTeam']
} | {
@ -20,8 +20,8 @@ export interface ITeamEditorState {
}
export class TeamEditor
extends React.PureComponent<ITeamEditorProps, ITeamEditorState> {
constructor(props: ITeamEditorProps) {
extends React.PureComponent<TTeamEditorProps, ITeamEditorState> {
constructor(props: TTeamEditorProps) {
super(props)
this.state = {
error: '',
@ -31,7 +31,7 @@ extends React.PureComponent<ITeamEditorProps, ITeamEditorState> {
getName(team?: ITeam) {
return team ? team.name : ''
}
componentWillReceiveProps(nextProps: ITeamEditorProps) {
componentWillReceiveProps(nextProps: TTeamEditorProps) {
if (nextProps.type === 'update') {
const {team} = nextProps
if (team !== (this.props as any).team) {

View File

@ -1,13 +1,13 @@
import React from 'react'
import {Button, Panel, PanelHeading, PanelBlock} from 'bloomer'
import {FaPlus, FaEdit, FaTimes} from 'react-icons/fa'
import {ITeam, ReadonlyRecord} from '@rondo/common'
import {ITeam, TReadonlyRecord} from '@rondo/common'
import {Link} from 'react-router-dom'
import {TeamActions} from './TeamActions'
import {TeamEditor} from './TeamEditor'
export interface ITeamListProps {
teamsById: ReadonlyRecord<number, ITeam>,
teamsById: TReadonlyRecord<number, ITeam>,
teamIds: ReadonlyArray<number>,
onAddTeam: TeamActions['createTeam']
onRemoveTeam: TeamActions['removeTeam']

View File

@ -1,6 +1,6 @@
import React from 'react'
import {History, Location} from 'history'
import {ITeam, IUserInTeam, ReadonlyRecord} from '@rondo/common'
import {ITeam, IUserInTeam, TReadonlyRecord} from '@rondo/common'
import {Panel, PanelBlock, PanelHeading} from 'bloomer'
import {Route, Switch} from 'react-router-dom'
import {TeamActions} from './TeamActions'
@ -24,11 +24,11 @@ export interface ITeamManagerProps {
fetchUsersInTeam: TeamActions['fetchUsersInTeam']
findUserByEmail: TeamActions['findUserByEmail']
teamsById: ReadonlyRecord<number, ITeam>
teamsById: TReadonlyRecord<number, ITeam>
teamIds: ReadonlyArray<number>
userKeysByTeamId: ReadonlyRecord<number, ReadonlyArray<string>>
usersByKey: ReadonlyRecord<string, IUserInTeam>
userKeysByTeamId: TReadonlyRecord<number, ReadonlyArray<string>>
usersByKey: TReadonlyRecord<string, IUserInTeam>
}
export class TeamManager extends React.PureComponent<ITeamManagerProps> {

View File

@ -1,17 +1,17 @@
import {
ITeam, IUserInTeam, ReadonlyRecord, indexBy, without,
ITeam, IUserInTeam, TReadonlyRecord, indexBy, without,
} from '@rondo/common'
import {TeamActionType} from './TeamActions'
import {GetResolvedAction} from '../actions'
import {TTeamAction} from './TeamActions'
import {TGetResolvedAction} from '../actions'
export interface ITeamState {
readonly error: string
readonly teamIds: ReadonlyArray<number>
readonly teamsById: ReadonlyRecord<number, ITeam>
readonly teamsById: TReadonlyRecord<number, ITeam>
readonly userKeysByTeamId: ReadonlyRecord<number, ReadonlyArray<string>>
readonly usersByKey: ReadonlyRecord<string, IUserInTeam>
readonly userKeysByTeamId: TReadonlyRecord<number, ReadonlyArray<string>>
readonly usersByKey: TReadonlyRecord<string, IUserInTeam>
}
const defaultState: ITeamState = {
@ -26,7 +26,7 @@ const defaultState: ITeamState = {
function removeUser(
state: ITeamState,
action: GetResolvedAction<TeamActionType, 'TEAM_USER_REMOVE'>,
action: TGetResolvedAction<TTeamAction, 'TEAM_USER_REMOVE'>,
) {
const {payload} = action
@ -52,7 +52,7 @@ function getUserKey(userInTeam: {userId: number, teamId: number}) {
return `${userInTeam.teamId}_${userInTeam.userId}`
}
export function Team(state = defaultState, action: TeamActionType): ITeamState {
export function Team(state = defaultState, action: TTeamAction): ITeamState {
switch (action.status) {
case 'pending':
return state

View File

@ -1,5 +1,5 @@
import React from 'react'
import {ITeam, IUser, IUserInTeam, ReadonlyRecord} from '@rondo/common'
import {ITeam, IUser, IUserInTeam, TReadonlyRecord} from '@rondo/common'
import {TeamActions} from './TeamActions'
import {FaUser, FaCheck, FaTimes} from 'react-icons/fa'
@ -18,8 +18,8 @@ export interface ITeamUsersProps {
onRemoveUser: TeamActions['removeUser']
team: ITeam
userKeysByTeamId: ReadonlyRecord<number, ReadonlyArray<string>>
usersByKey: ReadonlyRecord<string, IUserInTeam>
userKeysByTeamId: TReadonlyRecord<number, ReadonlyArray<string>>
usersByKey: TReadonlyRecord<string, IUserInTeam>
}
export interface ITeamUserProps {

View File

@ -1,7 +1,7 @@
import React from 'react'
import ReactDOM from 'react-dom'
import T from 'react-dom/test-utils'
import {IStateSelector} from '../redux'
import {TStateSelector} from '../redux'
import {Provider} from 'react-redux'
import {createStore} from '../store'
import {
@ -15,9 +15,9 @@ import {
interface IRenderParams<State, LocalState> {
reducers: ReducersMapObject<State, any>
select: IStateSelector<State, LocalState>
select: TStateSelector<State, LocalState>
// getComponent: (
// select: IStateSelector<State, LocalState>) => React.ComponentType<Props>,
// select: TStateSelector<State, LocalState>) => React.ComponentType<Props>,
// customJSX?: (
// Component: React.ComponentType<Props>,
// props: Props,
@ -65,7 +65,7 @@ export class TestUtils {
}
const withComponent = <Props extends {}>(
getComponent: (select: IStateSelector<State, LocalState>) =>
getComponent: (select: TStateSelector<State, LocalState>) =>
React.ComponentType<Props>,
) => {
const Component = getComponent(select)

View File

@ -1,4 +1,4 @@
export type IMethod = 'get'
export type TMethod = 'get'
| 'post'
| 'put'
| 'delete'

View File

@ -1,2 +0,0 @@
export type ReadonlyRecord<K extends string | number | symbol, V> =
Readonly<Record<K, V>>

View File

@ -9,7 +9,6 @@ export * from './IUser'
export * from './IUser'
export * from './IUserInTeam'
export * from './IUserTeam'
export * from './ReadonlyRecord'
export * from './URLFormatter'
export * from './indexBy'
export * from './types'

View File

@ -1,22 +1,25 @@
/**
* transform unknown into undefined
*/
export type Optional<T> = T extends {} ? T : undefined
export type TOptional<T> = T extends {} ? T : undefined
export type NonUndefinedPropertyNames<T> = {
export type TNonUndefinedPropertyNames<T> = {
[K in keyof T]: T[K] extends undefined ? never: K
}[keyof T]
export type OnlyRequired<T> = Pick<T, NonUndefinedPropertyNames<T>>
export type TOnlyRequired<T> = Pick<T, TNonUndefinedPropertyNames<T>>
export type NonUnknownPropertyNames<T> = {
export type TNonUnknownPropertyNames<T> = {
[K in keyof T]: T[K] extends {} ? K : never
}[keyof T]
export type OnlyDefined<T> = Pick<T, NonUnknownPropertyNames<T>>
export type TOnlyDefined<T> = Pick<T, TNonUnknownPropertyNames<T>>
/**
* Remove types from T that are not assignable to U
* https://www.typescriptlang.org/docs/handbook/advanced-types.html
*/
export type Filter<T, U> = T extends U ? T : never
export type TFilter<T, U> = T extends U ? T : never
export type TReadonlyRecord<K extends string | number | symbol, V> =
Readonly<Record<K, V>>

View File

@ -8,12 +8,12 @@ import {
Repository,
} from 'typeorm'
export type IConnectionGetter = () => Connection
export type TConnectionGetter = () => Connection
export class TransactionManager implements ITransactionManager {
constructor(
readonly ns: Namespace,
readonly getConnection: IConnectionGetter,
readonly getConnection: TConnectionGetter,
) {}
getEntityManager = (): EntityManager => {

View File

@ -17,10 +17,10 @@ export function pad(text: string, n: number, trim: boolean) {
return text
}
export type ILogLevel = 'error' | 'warn' | 'info' | 'debug' | 'verbose' | 'off'
export type TLogLevel = 'error' | 'warn' | 'info' | 'debug' | 'verbose' | 'off'
export interface IEnabledLoggers {
readonly [key: string]: ILogLevel
readonly [key: string]: TLogLevel
}
export interface IParams {
@ -48,9 +48,9 @@ export class LoggerFactory implements ILoggerFactory {
} = {}) {
const enabledLoggers = logs.split(',').reduce((logConfig, log) => {
const [key, value] = log.split(':')
logConfig[key] = (value || 'info') as ILogLevel
logConfig[key] = (value || 'info') as TLogLevel
return logConfig
}, {} as {[key: string]: ILogLevel})
}, {} as {[key: string]: TLogLevel})
const params = opts.split(',').reduce((o, key) => {
o[key] = true
@ -70,7 +70,7 @@ export class LoggerFactory implements ILoggerFactory {
this.getCorrelationId = () => ''
}
getLoggerLevel(name: string): ILogLevel {
getLoggerLevel(name: string): TLogLevel {
const {enabledLoggers} = this.options
const disabled = !!enabledLoggers['-' + name]
if (disabled) {

View File

@ -1,13 +1,13 @@
import {Authenticator as A, Passport} from 'passport'
import {IUserService} from '../services'
import {Strategy as LocalStrategy} from 'passport-local'
import {IHandler} from './IHandler'
import {THandler} from './THandler'
import {IMiddleware} from './IMiddleware'
export class Authenticator implements IMiddleware {
protected readonly passport: A
readonly handle: IHandler[]
readonly handle: THandler[]
constructor(protected readonly userService: IUserService) {
this.passport = new Passport() as any
@ -22,7 +22,7 @@ export class Authenticator implements IMiddleware {
]
}
withLogInPromise: IHandler = (req, res, next) => {
withLogInPromise: THandler = (req, res, next) => {
req.logInPromise = (user) => {
return new Promise((resolve, reject) => {
req.logIn(user, err => {
@ -72,7 +72,7 @@ export class Authenticator implements IMiddleware {
.catch(done)
}
authenticate(strategy: string | string[]): IHandler {
authenticate(strategy: string | string[]): THandler {
return (req, res, next) => {
return new Promise((resolve, reject) => {
this.passport.authenticate(strategy, (err: Error, user, info) => {

View File

@ -1,5 +1,5 @@
import Csurf from 'csurf'
import {IHandler} from './IHandler'
import {THandler} from './THandler'
import {IMiddleware} from './IMiddleware'
import {UrlWithStringQuery} from 'url'
@ -9,7 +9,7 @@ export interface ICSRFParams {
}
export class CSRFMiddleware implements IMiddleware {
readonly handle: IHandler
readonly handle: THandler
constructor(readonly params: ICSRFParams) {
this.handle = Csurf({

View File

@ -1,4 +1,4 @@
import {IErrorHandler} from './IErrorHandler'
import {TErrorHandler} from './TErrorHandler'
import {ILogger} from '../logger/ILogger'
import {IMiddleware} from './IMiddleware'
import {ValidationError} from '../validator'
@ -6,7 +6,7 @@ import {ValidationError} from '../validator'
export class ErrorApiHandler implements IMiddleware {
constructor(readonly logger: ILogger) {}
handle: IErrorHandler = (err, req, res, next) => {
handle: TErrorHandler = (err, req, res, next) => {
this.logger.error('%s An API error occurred: %s',
req.correlationId, err.stack)
const statusCode = this.getStatus(err)

View File

@ -1,11 +1,11 @@
import {IMiddleware} from './IMiddleware'
import {IErrorHandler} from './IErrorHandler'
import {ILogger} from '../logger/ILogger'
import {IMiddleware} from './IMiddleware'
import {TErrorHandler} from './TErrorHandler'
export class ErrorPageHandler implements IMiddleware {
constructor(readonly logger: ILogger) {}
handle: IErrorHandler = (err, req, res, next) => {
handle: TErrorHandler = (err, req, res, next) => {
this.logger.error(
'%s An error occurred: %s',
req.correlationId, err.stack)

View File

@ -1,6 +1,6 @@
import {IHandler} from './IHandler'
import {IErrorHandler} from './IErrorHandler'
import {THandler} from './THandler'
import {TErrorHandler} from './TErrorHandler'
export interface IMiddleware {
handle: IHandler | IHandler[] | IErrorHandler
handle: THandler | THandler[] | TErrorHandler
}

View File

@ -1,4 +1,4 @@
import {IHandler} from './IHandler'
import {THandler} from './THandler'
import {ILogger} from '../logger/ILogger'
import {IMiddleware} from './IMiddleware'
import shortid from 'shortid'
@ -6,7 +6,7 @@ import shortid from 'shortid'
export class RequestLogger implements IMiddleware {
constructor(protected readonly logger: ILogger) {}
handle: IHandler = (req, res, next) => {
handle: THandler = (req, res, next) => {
const start = Date.now()
req.correlationId = shortid.generate()
res.on('finish', () => {

View File

@ -1,5 +1,5 @@
import ExpressSession from 'express-session'
import {IHandler} from './IHandler'
import {THandler} from './THandler'
import {IMiddleware} from './IMiddleware'
import {ISession} from '../session/ISession'
import {ITransactionManager} from '../database/ITransactionManager'
@ -15,7 +15,7 @@ export interface ISessionOptions {
}
export class SessionMiddleware implements IMiddleware {
readonly handle: IHandler
readonly handle: THandler
constructor(readonly params: ISessionOptions) {
this.handle = ExpressSession({

View File

@ -1,4 +1,4 @@
import {Request, Response, NextFunction} from 'express'
export type IErrorHandler =
export type TErrorHandler =
(err: Error, req: Request, res: Response, next: NextFunction) => any

View File

@ -1,3 +1,3 @@
import {Request, Response, NextFunction} from 'express'
export type IHandler = (req: Request, res: Response, next: NextFunction) => any
export type THandler = (req: Request, res: Response, next: NextFunction) => any

View File

@ -1,4 +1,4 @@
import {Request, Response, NextFunction} from 'express'
export type IPromiseHandler<T> =
export type TPromiseHandler<T> =
(req: Request, res: Response, next: NextFunction) => Promise<T>

View File

@ -1,6 +1,6 @@
import shortid from 'shortid'
import {IMiddleware} from './IMiddleware'
import {IHandler} from './IHandler'
import {THandler} from './THandler'
import {Namespace} from 'cls-hooked'
export const CORRELATION_ID = 'CORRELATION_ID'
@ -8,7 +8,7 @@ export const CORRELATION_ID = 'CORRELATION_ID'
export class Transaction implements IMiddleware {
constructor(readonly ns: Namespace) {}
handle: IHandler = (req, res, next) => {
handle: THandler = (req, res, next) => {
const {ns} = this
ns.bindEmitter(req)
ns.bindEmitter(res)

View File

@ -1,10 +1,10 @@
import createError from 'http-errors'
import {Request} from 'express'
import {IHandler} from './IHandler'
import {THandler} from './THandler'
const isLoggedIn = (req: Request) => !!(req as any).user
export const ensureLoggedInApi: IHandler = (req, res, next) => {
export const ensureLoggedInApi: THandler = (req, res, next) => {
if (!isLoggedIn(req)) {
next(createError(401))
return
@ -12,7 +12,7 @@ export const ensureLoggedInApi: IHandler = (req, res, next) => {
next()
}
export const ensureLoggedInSite = (redirectTo: string): IHandler => {
export const ensureLoggedInSite = (redirectTo: string): THandler => {
return function _ensureLoggedInSite(req, res, next) {
if (!isLoggedIn(req)) {
res.redirect(redirectTo)

View File

@ -1,7 +1,7 @@
import {IHandler} from './IHandler'
import {IPromiseHandler} from './IPromiseHandler'
import {THandler} from './THandler'
import {TPromiseHandler} from './TPromiseHandler'
export function handlePromise<T>(endpoint: IPromiseHandler<T>): IHandler {
export function handlePromise<T>(endpoint: TPromiseHandler<T>): THandler {
return (req, res, next) => {
const promise = endpoint(req, res, next)
promise

View File

@ -1,13 +1,13 @@
export * from './Authenticator'
export * from './CSRFMiddleware'
export * from './ensureLoggedIn'
export * from './ErrorApiHandler'
export * from './ErrorPageHandler'
export * from './handlePromise'
export * from './IErrorHandler'
export * from './IHandler'
export * from './IMiddleware'
export * from './IPromiseHandler'
export * from './RequestLogger'
export * from './SessionMiddleware'
export * from './TErrorHandler'
export * from './THandler'
export * from './TPromiseHandler'
export * from './Transaction'
export * from './ensureLoggedIn'
export * from './handlePromise'

View File

@ -1,6 +1,6 @@
import express from 'express'
import {IRoutes, IMethod} from '@rondo/common'
import {ITypedHandler} from './ITypedHandler'
import {IRoutes, TMethod} from '@rondo/common'
import {TTypedHandler} from './TTypedHandler'
export class AsyncRouter<R extends IRoutes> {
readonly router: express.Router
@ -11,18 +11,18 @@ export class AsyncRouter<R extends IRoutes> {
this.use = this.router.use.bind(this.router) as any
}
protected addRoute<M extends IMethod, P extends keyof R & string>(
protected addRoute<M extends TMethod, P extends keyof R & string>(
method: M,
path: P,
handler: ITypedHandler<R, P, M>,
handler: TTypedHandler<R, P, M>,
) {
const addRoute = this.router[method].bind(this.router as any)
addRoute(path, this.wrapHandler(handler))
}
protected wrapHandler<M extends IMethod, P extends keyof R & string>(
handler: ITypedHandler<R, P, M>,
protected wrapHandler<M extends TMethod, P extends keyof R & string>(
handler: TTypedHandler<R, P, M>,
): express.RequestHandler {
return (req, res, next) => {
handler(req, res, next)
@ -35,43 +35,43 @@ export class AsyncRouter<R extends IRoutes> {
get<P extends keyof R & string>(
path: P,
handler: ITypedHandler<R, P, 'get'>,
handler: TTypedHandler<R, P, 'get'>,
) {
this.addRoute('get', path, handler)
}
post<P extends keyof R & string>(
path: P,
handler: ITypedHandler<R, P, 'post'>,
handler: TTypedHandler<R, P, 'post'>,
) {
this.addRoute('post', path, handler)
}
put<P extends keyof R & string>(
path: P, handler: ITypedHandler<R, P, 'put'>,
path: P, handler: TTypedHandler<R, P, 'put'>,
) {
this.addRoute('put', path, handler)
}
delete<P extends keyof R & string>(
path: P, handler: ITypedHandler<R, P, 'delete'>) {
path: P, handler: TTypedHandler<R, P, 'delete'>) {
this.addRoute('delete', path, handler)
}
head<P extends keyof R & string>(
path: P,
handler: ITypedHandler<R, P, 'head'>,
handler: TTypedHandler<R, P, 'head'>,
) {
this.addRoute('head', path, handler)
}
options<P extends keyof R & string>(
path: P, handler: ITypedHandler<R, P, 'options'>) {
path: P, handler: TTypedHandler<R, P, 'options'>) {
this.addRoute('options', path, handler)
}
patch<P extends keyof R & string>(
path: P, handler: ITypedHandler<R, P, 'patch'>) {
path: P, handler: TTypedHandler<R, P, 'patch'>) {
this.addRoute('patch', path, handler)
}

View File

@ -1,11 +1,11 @@
import express from 'express'
import {IRoutes, IMethod} from '@rondo/common'
import {IRoutes, TMethod} from '@rondo/common'
import {ITypedRequest} from './ITypedRequest'
export type ITypedHandler<
export type TTypedHandler<
R extends IRoutes,
P extends keyof R,
M extends IMethod
M extends TMethod
> = (
req: ITypedRequest<R[P][M]>,
res: express.Response,

View File

@ -1,16 +1,16 @@
import express from 'express'
import {AsyncRouter} from './AsyncRouter'
import {IRoutes, IMethod} from '@rondo/common'
import {IRoutes, TMethod} from '@rondo/common'
import {ITransactionManager} from '../database/ITransactionManager'
import {ITypedHandler} from './ITypedHandler'
import {TTypedHandler} from './TTypedHandler'
export class TransactionalRouter<R extends IRoutes> extends AsyncRouter<R> {
constructor(readonly transactionManager: ITransactionManager) {
super()
}
protected wrapHandler<M extends IMethod, P extends keyof R & string>(
handler: ITypedHandler<R, P, M>,
protected wrapHandler<M extends TMethod, P extends keyof R & string>(
handler: TTypedHandler<R, P, M>,
): express.RequestHandler {
return async (req, res, next) => {
await this.transactionManager

View File

@ -1,4 +1,4 @@
export * from './AsyncRouter'
export * from './ITypedHandler'
export * from './TTypedHandler'
export * from './ITypedRequest'
export * from './TransactionalRouter'

View File

@ -1,9 +1,9 @@
import {IHandler} from '../middleware/IHandler'
import {THandler} from '../middleware/THandler'
import {AsyncRouter} from '../router'
import {IRoutes} from '@rondo/common'
export abstract class BaseRoute<T extends IRoutes> {
readonly handle: IHandler
readonly handle: THandler
constructor(protected readonly t: AsyncRouter<T>) {
this.handle = t.router

View File

@ -9,11 +9,11 @@ type CallbackErr = (err?: any) => void
export interface ISessionStoreOptions<S extends ISession> {
readonly ttl: number
readonly cleanup: number
readonly getRepository: IRepositoryFactory<S>
readonly getRepository: TRepositoryFactory<S>
buildSession(sessionData: SessionData, session: ISession): S
}
export type IRepositoryFactory<T> = () => Repository<T>
export type TRepositoryFactory<T> = () => Repository<T>
// TODO casting as any because TypeScript complains. Looks like this is a
// bug in TypeScript 3.2.2
@ -22,7 +22,7 @@ export type IRepositoryFactory<T> = () => Repository<T>
// https://github.com/Microsoft/TypeScript/issues/21592
export class SessionStore<S extends ISession> extends Store {
protected readonly getRepository: IRepositoryFactory<S>
protected readonly getRepository: TRepositoryFactory<S>
constructor(
protected readonly options: ISessionStoreOptions<S>,

View File

@ -1,6 +1,6 @@
import supertest from 'supertest'
import {
IMethod,
TMethod,
IRoutes,
URLFormatter,
} from '@rondo/common'
@ -13,7 +13,7 @@ interface ITest extends Omit<Omit<supertest.Test, 'then'>, 'catch'> {}
interface IResponse<
R extends IRoutes,
P extends keyof R,
M extends IMethod,
M extends TMethod,
> extends supertest.Response {
body: R[P][M]['response']
header: {[key: string]: string}
@ -22,7 +22,7 @@ interface IResponse<
interface IRequest<
R extends IRoutes,
P extends keyof R,
M extends IMethod,
M extends TMethod,
> extends ITest, Promise<IResponse<R, P, M>> {
send(value: R[P][M]['body'] | string): this
expect(status: number, body?: any): this
@ -37,7 +37,7 @@ interface IRequest<
interface IRequestOptions<
R extends IRoutes,
P extends keyof R,
M extends IMethod,
M extends TMethod,
> {
params?: R[P][M]['params'],
query?: R[P][M]['query'],
@ -62,7 +62,7 @@ export class RequestTester<R extends IRoutes> {
return this
}
request<M extends IMethod, P extends keyof R & string>(
request<M extends TMethod, P extends keyof R & string>(
method: M, path: P, options: IRequestOptions<R, P, 'post'> = {},
)
: IRequest<R, P, M> {