Front-end tech leader
Stefano Magni
TypeScript’ Discriminated Unions
Straightforward React components
Explicit State Machines
Cypress integration tests
type Order = {
name: string
description?: string
at: Location
} & ({
status: 'ready'
} | {
status: 'inProgress'
expectedDelivery: Date
} | {
status: 'complete'
expectedDelivery: Date
deliveredOn: Date
})
type Order = {
status: string
name: string
description?: string
at?: Location
expectedDelivery?: Date
deliveredOn?: Date
}
type Order = {
name: string
description?: string
at: Location
} & ({
status: 'ready'
} | {
status: 'inProgress'
expectedDelivery: Date
} | {
status: 'complete'
expectedDelivery: Date
deliveredOn: Date
})
type Order = {
status: string
name: string
description?: string
at?: Location
expectedDelivery?: Date
deliveredOn?: Date
}
type Order = {
name: string
description?: string
at: Location
} & ({
status: 'ready'
} | {
status: 'inProgress'
expectedDelivery: Date
} | {
status: 'complete'
expectedDelivery: Date
deliveredOn: Date
})
type Order = {
status: string
name: string
description?: string
at?: Location
expectedDelivery?: Date
deliveredOn?: Date
}
function createEmailMessage(order: Order) {
if (order.expectedDelivery) {
return `${order.name} will be delivered at ${order.expectedDelivery}`
}
if (order.deliveredOn) {
return `${order.name} has been delivered on ${order.deliveredOn}`
}
if (!order.expectedDelivery && !order.deliveredOn) {
return `${order.name} is at ${order.at}`
}
}
type Order = {
name: string
description?: string
at: Location
} & ({
status: 'ready'
} | {
status: 'inProgress'
expectedDelivery: Date
} | {
status: 'complete'
expectedDelivery: Date
deliveredOn: Date
})
type Order = {
status: string
name: string
description?: string
at?: Location
expectedDelivery?: Date
deliveredOn?: Date
}
function createEmailMessage(order: Order) {
switch(order.status) {
case 'ready':
return `${order.name} is at ${order.at}`
case 'inProgress':
return `${order.name} will be delivered at ${order.expectedDelivery}`
case 'complete':
return `${order.name} has been delivered at ${order.deliveredOn}`
}
}
function createEmailMessage(order: Order) {
// ^? createEmailMessage(order: Order): string | undefined
if (order.expectedDelivery) {
return `${order.name} will be delivered ${order.expectedDelivery}`
}
if (order.deliveredOn) {
return `${order.name} has been delivered on ${order.deliveredOn}`
}
if (!order.expectedDelivery && !order.deliveredOn) {
return `${order.name} is at ${order.at}`
}
}
function createEmailMessage(order: Order) {
// ^? createEmailMessage(order: Order): string
switch(order.status) {
case 'ready':
return `${order.name} is at ${order.at}`
case 'inProgress':
return `${order.name} will be delivered ${order.expectedDelivery}`
case 'complete':
return `${order.name} has been delivered at ${order.deliveredOn}`
}
}
function createEmailMessage(order: Order) {
// ^? createEmailMessage(order: Order): string | undefined
if (order.expectedDelivery) {
return `${order.name} will be delivered ${order.expectedDelivery}`
}
if (order.deliveredOn) {
return `${order.name} has been delivered on ${order.deliveredOn}`
}
if (!order.expectedDelivery && !order.deliveredOn) {
return `${order.name} is at ${order.at}`
}
}
function createEmailMessage(order: Order) { /* ... */ }
// ^? createEmailMessage(order: Order): string
const message = createEmailMessage(order)
sendEmail(message)
function createEmailMessage(order: Order) { /* ... */ }
// ^? createEmailMessage(order: Order): string | undefined
const message = createEmailMessage(order)
if(message) {
sendEmail(message)
}
export function RenderOrder() {
const [order, setOrder] = useState<Order | undefined>()
useEffect(() => {
fetch('https://api.yourdomain.com/latest-order')
.then(response => response.json())
.then(order => setOrder(order))
}, [])
const onSendEmailClick = useCallback(() => {
if (!order) return
const message = createEmailMessage(order)
if (message) {
sendEmail(message)
}
}, [order])
if (!order) return null
return (
<div>
<p>
{order.name} ({order.status})
</p>
{order.description && <p>{order.description}</p>}
{!order.deliveredOn && order.expectedDelivery && (
<p>Expected delivery: {order.expectedDelivery}</p>
)}
{order.deliveredOn && <p>Delivered on: {order.deliveredOn}</p>}
<button onClick={onSendEmailClick}>Send email</button>
</div>
)
}
export function RenderOrder() {
const [order, setOrder] = useState<Order | undefined>()
useEffect(() => {
fetch('https://api.yourdomain.com/latest-order')
.then(response => response.json())
.then(order => setOrder(order))
}, [])
const onSendEmailClick = useCallback(() => {
if (!order) return
const message = createEmailMessage(order)
if (message) {
sendEmail(message)
}
}, [order])
if (!order) return null
return (
<div>
<p>
{order.name} ({order.status})
</p>
{order.description && <p>{order.description}</p>}
{!order.deliveredOn && order.expectedDelivery && (
<p>Expected delivery: {order.expectedDelivery}</p>
)}
{order.deliveredOn && <p>Delivered on: {order.deliveredOn}</p>}
<button onClick={onSendEmailClick}>Send email</button>
</div>
)
}
export function RenderOrder() {
const fetchStatus = useFetchOrder()
if (fetchStatus.status === 'loading')
return <p>Loading...</p>
const order = fetchStatus.order
switch (order.status) {
case 'ready':
return <ReadyOrder order={order} />
case 'inProgress':
return <InProgressOrder order={order} />
case 'complete':
return <CompleteOrder order={order} />
}
}
export function RenderOrder() {
const fetchStatus = useFetchOrder()
if (fetchStatus.status === 'loading')
return <p>Loading...</p>
const order = fetchStatus.order
switch (order.status) {
case 'ready':
return <ReadyOrder order={order} />
case 'inProgress':
return <InProgressOrder order={order} />
case 'complete':
return <CompleteOrder order={order} />
}
}
type Props = {
order: Order
}
export function CompleteOrder(props: Props) {
const { order } = props
if (order.status !== 'complete') return null
const { name, description, deliveredOn } = order
return (
<div>
<OrderHeading name={name} description={description} />
<p>Delivered on: {deliveredOn}</p>
<SendEmailButton order={order} />
</div>
)
}
export function RenderOrder() {
const fetchStatus = useFetchOrder()
if (fetchStatus.status === 'loading')
return <p>Loading...</p>
const order = fetchStatus.order
switch (order.status) {
case 'ready':
return <ReadyOrder order={order} />
case 'inProgress':
return <InProgressOrder order={order} />
case 'complete':
return <CompleteOrder order={order} />
}
}
type Props = {
order: Order
}
export function CompleteOrder(props: Props) {
const { order } = props
if (order.status !== 'complete') return null
const { name, description, deliveredOn } = order
return (
<div>
<OrderHeading name={name} description={description} />
<p>Delivered on: {deliveredOn}</p>
<SendEmailButton order={order} />
</div>
)
}
export function RenderOrder() {
const fetchStatus = useFetchOrder()
if (fetchStatus.status === 'loading')
return <p>Loading...</p>
const order = fetchStatus.order
switch (order.status) {
case 'ready':
return <ReadyOrder order={order} />
case 'inProgress':
return <InProgressOrder order={order} />
case 'complete':
return <CompleteOrder order={order} />
}
}
type CompletedOrder =
Extract<Order, { status: 'complete' }>
type Props = {
order: CompletedOrder
}
export function CompleteOrder(props: Props) {
const { order } = props
const { name, description, deliveredOn } = order
return (
<div>
<OrderHeading name={name} description={description} />
<p>Delivered on: {deliveredOn}</p>
<SendEmailButton order={order} />
</div>
)
}
export function RenderOrder() {
const fetchStatus = useFetchOrder()
if (fetchStatus.status === 'loading')
return <p>Loading...</p>
const order = fetchStatus.order
switch (order.status) {
case 'ready':
return <ReadyOrder order={order} />
case 'inProgress':
return <InProgressOrder order={order} />
case 'complete':
return <CompleteOrder order={order} />
}
}
type CompletedOrder =
Extract<Order, { status: 'complete' }>
type Props = {
order: CompletedOrder
}
export function CompleteOrder(props: Props) {
const { order } = props
const { name, description, deliveredOn } = order
return (
<div>
<OrderHeading name={name} description={description} />
<p>Delivered on: {deliveredOn}</p>
<SendEmailButton order={order} />
</div>
)
}
The intersection among the previous points
Navigation
Shopify connection status
Admin privileges
The intersection among the previous points
type AppStatus =
| { status: 'showConnect' }
| { status: 'showNonAdminError' }
| { status: 'showSelectOrdersInstructions' }
| // etc.
Navigation
Shopify connection status
Admin privileges
The intersection among the previous points
type AppStatus =
| { status: 'showConnect' }
| { status: 'showNonAdminError' }
| { status: 'showSelectOrdersInstructions' }
| // etc.
useEffect(() => {
switch (currentPage) {
case 'connect':
Navigation
Shopify connection status
Admin privileges
The intersection among the previous points
type AppStatus =
| { status: 'showConnect' }
| { status: 'showNonAdminError' }
| { status: 'showSelectOrdersInstructions' }
| // etc.
useEffect(() => {
switch (currentPage) {
case 'connect':
switch (howUserNavigated('connect')) {
// ------------------------------------------------------------------
// SCENARIO: the server redirected the user to the connect page
// ------------------------------------------------------------------
case 'sentFromServer':
// ------------------------------------------------------------------
// SCENARIO: the user navigated directly to the connect page
// ------------------------------------------------------------------
case 'directNavigation':
Navigation
Shopify connection status
Admin privileges
The intersection among the previous points
type AppStatus =
| { status: 'showConnect' }
| { status: 'showNonAdminError' }
| { status: 'showSelectOrdersInstructions' }
| // etc.
useEffect(() => {
switch (currentPage) {
case 'connect':
switch (howUserNavigated('connect')) {
// ------------------------------------------------------------------
// SCENARIO: the server redirected the user to the connect page
// ------------------------------------------------------------------
case 'sentFromServer':
switch (connectStatus.status) {
case 'notRequestedYet':
case 'failed':
case 'succeeded':
}
break
// ------------------------------------------------------------------
// SCENARIO: the user navigated directly to the connect page
// ------------------------------------------------------------------
case 'directNavigation':
Navigation
Shopify connection status
Admin privileges
The intersection among the previous points
type AppStatus =
| { status: 'showConnect' }
| { status: 'showNonAdminError' }
| { status: 'showSelectOrdersInstructions' }
| // etc.
useEffect(() => {
switch (currentPage) {
case 'connect':
switch (howUserNavigated('connect')) {
// ------------------------------------------------------------------
// SCENARIO: the server redirected the user to the connect page
// ------------------------------------------------------------------
case 'sentFromServer':
switch (connectStatus.status) {
case 'notRequestedYet':
case 'failed':
// when the connect succeeds, this effect is re-triggered
setStatus({ status: 'showConnect' })
break
case 'succeeded':
setStatus({ status: 'showSelectOrdersInstructions' })
break
}
break
// ------------------------------------------------------------------
// SCENARIO: the user navigated directly to the connect page
// ------------------------------------------------------------------
case 'directNavigation':
redirectTo('home') // as a result, this effect is re-triggered
break
}
break
Navigation
Shopify connection status
Admin privileges
Tests - What data the app exchanges with the server
React components - App's structure
Tests - What the app does
State Machine - How the app works
Types - Domain-related knowledge
Front-end tech leader
Stefano Magni