Skip to content

Commit

Permalink
style: apply prettier
Browse files Browse the repository at this point in the history
  • Loading branch information
Hotell committed Jun 27, 2018
1 parent 928d11a commit c5087e6
Show file tree
Hide file tree
Showing 16 changed files with 131 additions and 131 deletions.
12 changes: 6 additions & 6 deletions 2018-02/private-properties-in-webcomponents/blogpost.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ In this article we will focus primarily on [**Unique Symbol Types**](https://git

For our demonstration purpose, we will implement a simple `Toggleable Custom Element` with following featurs:

* it is both stateful and controllable component
* public API contains of 2 props: `title` and `show` and content projection via `slot`
* onClick it will toggle visibility of projected content
- it is both stateful and controllable component
- public API contains of 2 props: `title` and `show` and content projection via `slot`
- onClick it will toggle visibility of projected content

**Usage:**

Expand All @@ -26,9 +26,9 @@ Ok let's implement our `Toggleable` Custom Element:

As we know, standard pattern to impement Custom Element props is following

* internal "private" class property which keeps current property value
* getter to that "private" property for public use
* setter for "private" property for public use
- internal "private" class property which keeps current property value
- getter to that "private" property for public use
- setter for "private" property for public use

So let's say for our `title` prop following needs to be implemented

Expand Down
52 changes: 26 additions & 26 deletions 2018-02/typesafe-redux/blogpost.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ At that time ( pre TS 2.8 era ) there wasn't a clean solution how to get the ret

You had to do it like this:

* define type definition first,
* then implement action creator with return type annotated with your defined type
* when you changed one thing, you needed to manually update other and vice-versa, bleh...
- define type definition first,
- then implement action creator with return type annotated with your defined type
- when you changed one thing, you needed to manually update other and vice-versa, bleh...

```ts
// you need to define the shape first
Expand Down Expand Up @@ -44,11 +44,11 @@ Thanks to this addition, we can create new powerfull mapped types, let's say, fo
Wait a second! It turns out we don't have to create anything at all, 'cause they are already a part of TS 2.8! We've got following new mapped types at our disposal:

* `Exclude<T, U>` -- Exclude from T those types that are assignable to U.
* `Extract<T, U>` -- Extract from T those types that are assignable to U.
* `NonNullable<T>` -- Exclude null and undefined from T.
* `ReturnType<T>` -- Obtain the return type of a function type.
* `InstanceType<T>` -- Obtain the instance type of a constructor function type.
- `Exclude<T, U>` -- Exclude from T those types that are assignable to U.
- `Extract<T, U>` -- Extract from T those types that are assignable to U.
- `NonNullable<T>` -- Exclude null and undefined from T.
- `ReturnType<T>` -- Obtain the return type of a function type.
- `InstanceType<T>` -- Obtain the instance type of a constructor function type.

> for more info (check out this PR)[https://github.com/Microsoft/TypeScript/pull/21847]
Expand Down Expand Up @@ -124,11 +124,11 @@ Now our inferred type is correct

**PROS:**

* action type is inferred from implementation and because of that stays in sync!
- action type is inferred from implementation and because of that stays in sync!

**CONS:**

* explicitly casting `type` property within action creator
- explicitly casting `type` property within action creator

## Reducing the action boilerplate (createAction)

Expand Down Expand Up @@ -177,13 +177,13 @@ type SetAgeAction = ReturnType<typeof setAge>

**PROS:**

* ( as before ) action type is inferred from implementation and because of that, it stays in sync!
* we don't have to cast our type
* more concise than before
- ( as before ) action type is inferred from implementation and because of that, it stays in sync!
- we don't have to cast our type
- more concise than before

**CONS:**

* none I guess ? :)
- none I guess ? :)

## Reducing the action boilerplate further (action)

Expand Down Expand Up @@ -248,13 +248,13 @@ With that our `DoSomethingAction` will have following type:
**PROS:**
* ( as before ) action type is inferred from implementation and because of that, it stays in sync!
* ( as before ) we don't have to cast our type
* even more concise than `createAction`
- ( as before ) action type is inferred from implementation and because of that, it stays in sync!
- ( as before ) we don't have to cast our type
- even more concise than `createAction`
**CONS:**
* if we wanna provide payload, we have to explicitly declare `typeof SET_AGE` as 1st generic argument, because TS isn't able to do that for us properly ( it will flatten string literal to just simple `string`)
- if we wanna provide payload, we have to explicitly declare `typeof SET_AGE` as 1st generic argument, because TS isn't able to do that for us properly ( it will flatten string literal to just simple `string`)
## Reducing the action boilerplate by using classes
Expand All @@ -278,22 +278,22 @@ Everything is defined once -> implementaion and action type definition. Elegant
> This can be mitigated via custom middleware, which shalow copies created instance to pure Object
>
> ```ts
> export const actionToPlainObject: MiddlewareFn<{}, Action> = store => next => action =>
> export const actionToPlainObject: MiddlewareFn<{}, Action> = (store) => (next) => (action) =>
> next({ ...action })
> ```
>
> If you're using @ngrx/store you don't need to do this, because it's only restriction is to be an serializable object
**PROS:**
* implementation is also type definition because structural origin of TypeScript Classes
* concise and elegant
- implementation is also type definition because structural origin of TypeScript Classes
- concise and elegant
**CONS:**
* constructor parameter named genericaly `payload`, which may not be very descriptive if payload is a primitive type
* (if you're using redux ) you need to provide custom middleware for flattening custom class instance to pure object
* using `new SetAgeAction(18)` may feel strange or just wrong to some functional purists, I don't mind personaly 😎, it makes it even more visible within component code that I'm creating a FSA
- constructor parameter named genericaly `payload`, which may not be very descriptive if payload is a primitive type
- (if you're using redux ) you need to provide custom middleware for flattening custom class instance to pure object
- using `new SetAgeAction(18)` may feel strange or just wrong to some functional purists, I don't mind personaly 😎, it makes it even more visible within component code that I'm creating a FSA
## And the winner is
Expand Down Expand Up @@ -381,8 +381,8 @@ With that said, let’s grab some beer and popcorn and enjoy your 100% type-safe
TypeScript 2.8 comes with very important new features:
* conditional types
* new default conditional mapped types, from which we can leverage `ReturnType<T>` to get return types of a function
- conditional types
- new default conditional mapped types, from which we can leverage `ReturnType<T>` to get return types of a function
Thanks to these new features, TypeScript is able to infer action type of our action creator implementation,
so we don't have to duplicate our work and keep type definition and implementaion in sync.
Expand Down
8 changes: 4 additions & 4 deletions 2018-02/typesafe-redux/src/epic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@ import { ActionsOfType } from './types'

type SetAgeAction = ActionsOfType<Actions, typeof SET_AGE>

const epic: Epic<Actions, State> = actions$ => {
const epic: Epic<Actions, State> = (actions$) => {
return actions$.pipe(
ofType<Actions, SetAgeAction>(SET_AGE),
map(action => {
map((action) => {
const { type, payload: newAge } = action
return Actions.reloadUrl()
})
)
}

const epicWithChainOfType: Epic<Actions, State> = actions$ => {
const epicWithChainOfType: Epic<Actions, State> = (actions$) => {
return actions$.ofType<SetAgeAction>(SET_AGE).pipe(
map(action => {
map((action) => {
const { type, payload: newAge } = action
return Actions.reloadUrl()
})
Expand Down
8 changes: 4 additions & 4 deletions 2018-02/typesafe-redux/src/epics-with-enums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@ import { ActionsOfType } from './types'

type SetAgeAction = ActionsOfType<Actions, ActionTypes.SET_AGE>

const epic: Epic<Actions, State> = actions$ => {
const epic: Epic<Actions, State> = (actions$) => {
return actions$.pipe(
ofType<Actions, SetAgeAction>(ActionTypes.SET_AGE),
map(action => {
map((action) => {
const { type, payload: newAge } = action
return Actions.reloadUrl()
})
)
}

const epicWithChainOfType: Epic<Actions, State> = actions$ => {
const epicWithChainOfType: Epic<Actions, State> = (actions$) => {
return actions$.ofType<SetAgeAction>(ActionTypes.SET_AGE).pipe(
map(action => {
map((action) => {
const { type, payload: newAge } = action
return Actions.reloadUrl()
})
Expand Down
4 changes: 2 additions & 2 deletions 2018-02/typesafe-redux/src/epics-with-improved-of-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ import { SET_AGE, Actions } from './actions'
import { State } from './store'

// BEHOLD 100% type safe epic ! I ❤️ love it !
const epic: Epic<Actions, State> = actions$ => {
const epic: Epic<Actions, State> = (actions$) => {
return actions$.pipe(
// ofType(ActionTypes.SET_AGE),
ofType(SET_AGE),
map(action => {
map((action) => {
const { type, payload: newAge } = action
return Actions.reloadUrl()
})
Expand Down
2 changes: 1 addition & 1 deletion 2018-02/typesafe-redux/src/of-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ export function ofType<
>(t1: T1, t2: T2, t3: T3): OperatorFunction<V, ActionsOfType<V, T1 | T2 | T3 | T4>>
export function ofType(...types: string[]) {
return function(source: Observable<any>) {
return source.pipe(filter(action => types.indexOf(action.type) !== -1)) as any
return source.pipe(filter((action) => types.indexOf(action.type) !== -1)) as any
}
}
32 changes: 16 additions & 16 deletions 2018-02/ultimate-react-component-patterns/blogpost.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,9 +206,9 @@ that it is defined by `Component.defaultProps` React construct.

To satisfy TS compiler we can use 3 techniques:

* use **Bang** operator to explicitly tell compiler that this won't be `undefined` within our render, although it is optional, like this: `<button onClick={handleClick!}>{children}</button>`
* use **conditional statements/ternary operator** to make compiler understand that some particular prop is not undefined: `<button onClick={handleClick ? handleClick: undefined}>{children}</button>`
* create reusable `withDefaultProps` High order function, which will update our props type definition and will set our default props. This is the most clean solution, IMHO
- use **Bang** operator to explicitly tell compiler that this won't be `undefined` within our render, although it is optional, like this: `<button onClick={handleClick!}>{children}</button>`
- use **conditional statements/ternary operator** to make compiler understand that some particular prop is not undefined: `<button onClick={handleClick ? handleClick: undefined}>{children}</button>`
- create reusable `withDefaultProps` High order function, which will update our props type definition and will set our default props. This is the most clean solution, IMHO

```ts
export const withDefaultProps = <P extends object, DP extends Partial<P> = Partial<P>>(
Expand Down Expand Up @@ -371,7 +371,7 @@ const initialState = { show: false }
type State = Readonly<typeof initialState>
```
* here we are declaring our state as in previous examples, nothing new
- here we are declaring our state as in previous examples, nothing new
Now we need to define our component props ( note that we are using Partial mapped type, as we know that all props are gonna be optional, instead of annotating every prop manually by `?` operator ):
Expand All @@ -395,8 +395,8 @@ type ToggleableComponentProps = { show: State['show']; toggle: Toggleable['toggl
Again we are using the power of typeScript and **lookup types**, so we don't have to repeat ourselves when defining types:
* `show: State['show']` we are creating our `show` prop type by leveraging existing type definition within our state
* `toggle: Toggleable['toggle']` we are leveraging type inference and structural nature of classes within TS by getting the type from our method implementation! nice and indeed powerful!
- `show: State['show']` we are creating our `show` prop type by leveraging existing type definition within our state
- `toggle: Toggleable['toggle']` we are leveraging type inference and structural nature of classes within TS by getting the type from our method implementation! nice and indeed powerful!
The rest of the implementation is straightforward, standard _render props/children as function_ pattern:
Expand Down Expand Up @@ -549,9 +549,9 @@ Now with that done, let's define our new API - `component` prop.

We need update our props API.

* `children` can be now function or ReactNode ( when component prop is used)
* `component` is our new API which accepts component that needs to implement `ToggleableComponentProps` on it's props and it needs to be generic and set to `any`, so if arbitrary component that implements other properties than `ToggleableComponentProps` will pass TS validaion
* `props` we are introducing props property for passing down arbitrary props, this is a common pattern. It is defined as index type with any type, so we are loosing here strict type safety...
- `children` can be now function or ReactNode ( when component prop is used)
- `component` is our new API which accepts component that needs to implement `ToggleableComponentProps` on it's props and it needs to be generic and set to `any`, so if arbitrary component that implements other properties than `ToggleableComponentProps` will pass TS validaion
- `props` we are introducing props property for passing down arbitrary props, this is a common pattern. It is defined as index type with any type, so we are loosing here strict type safety...

```tsx
// We need create defaultProps with our arbitrary prop type -> props which is gonna be empty object by default
Expand Down Expand Up @@ -723,9 +723,9 @@ Let's implement our HOC:

We need to create:

* displayName ( so we get nice debugging within devtools)
* WrappedComponent ( so we can access original component - useful for testing )
* leverage `hoistNonReactStatics` from `hoist-non-react-statics` npm package
- displayName ( so we get nice debugging within devtools)
- WrappedComponent ( so we can access original component - useful for testing )
- leverage `hoistNonReactStatics` from `hoist-non-react-statics` npm package

```tsx
import React, { ComponentType, Component } from 'react'
Expand Down Expand Up @@ -756,7 +756,7 @@ export const withToogleable = <OriginalProps extends object>(
const { ...rest } = this.props

return (
<Toggleable render={renderProps => <UnwrappedComponent {...rest} {...renderProps} />} />
<Toggleable render={(renderProps) => <UnwrappedComponent {...rest} {...renderProps} />} />
)
}
}
Expand Down Expand Up @@ -933,7 +933,7 @@ export const withToogleable = <OriginalProps extends object>(
return (
<Toggleable
show={show}
render={renderProps => <UnwrappedComponent {...rest} {...renderProps} />}
render={(renderProps) => <UnwrappedComponent {...rest} {...renderProps} />}
/>
)
}
Expand All @@ -957,7 +957,7 @@ All demos can be found at [my Github repo](https://github.com/Hotell/blogposts/t
Also it is very important to realise, that type safety within templates like demonstrated in this article, is possible only within libraries that use VDOM/JSX
* Angular templates with Language service provide type safety, but soundness fails on simple constructs like checking within ngFor etc...
* Vue has nothing like Angular implemented yet for templates, so their templates and data binding are just magical strings ( but this may change in the future. Although you can use VDOM for templates it's cumbersome to use because various types of props definition ( "snabdom takes the blame..." ) )
- Angular templates with Language service provide type safety, but soundness fails on simple constructs like checking within ngFor etc...
- Vue has nothing like Angular implemented yet for templates, so their templates and data binding are just magical strings ( but this may change in the future. Although you can use VDOM for templates it's cumbersome to use because various types of props definition ( "snabdom takes the blame..." ) )
As always, don't hesitate to ping me if you have any questions here or on twitter (my handle [@martin_hotell](https://twitter.com/martin_hotell)) and besides that, happy type checking folks and 'till next time! Cheers!
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export function withToggle<OriginalProps>(
)
}
private toggle = (event: MouseEvent<HTMLElement>) =>
this.setState(prevState => ({ show: !prevState.show }))
this.setState((prevState) => ({ show: !prevState.show }))
}

return hoistNonReactStatics(WithToggle, UnwrappedComponent as any) as ComponentType<Props>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,5 @@ export class Menu extends Component<{}, State> {
}

private toggleShowContents = () =>
this.setState(prevState => ({ showContents: !prevState.showContents }))
this.setState((prevState) => ({ showContents: !prevState.showContents }))
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export const withToogleable = <OriginalProps extends object>(
return (
<Toggleable
show={show}
render={renderProps => <UnwrappedComponent {...rest} {...renderProps} />}
render={(renderProps) => <UnwrappedComponent {...rest} {...renderProps} />}
/>
)
}
Expand Down
Loading

0 comments on commit c5087e6

Please sign in to comment.