Skip to content

Instantly share code, notes, and snippets.

@rluiten
Last active October 2, 2020 09:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rluiten/3b6bc6eff5b43860e0e31ff1196c080c to your computer and use it in GitHub Desktop.
Save rluiten/3b6bc6eff5b43860e0e31ff1196c080c to your computer and use it in GitHub Desktop.
Example of filterOptions, EqualTypes.
// prettier-ignore
// Compare types for equivalence
// Reference: https://github.com/Microsoft/TypeScript/issues/27024
//
// Better fix coming in Typescript 4 ? my read isn't clear on this
// Reference: https://github.com/microsoft/TypeScript/issues/37314#issuecomment-598459316
export type EqualTypes<X extends unknown, Y extends unknown> =
(<T>() => T extends X ? 1 : 2) extends
(<T>() => T extends Y ? 1 : 2) ? true : false;
import { EqualTypes } from './EqualTypes'
// I tripped and dug a rabbit hole in Typescript land today.
// I wanted a way to have my Type and eat it to.
// Please feel free to critique or improve or point me at a better way.
//
// The requirements.
// Declares a set of strings to map to another set of strings.
// Declare the order to iterate over the domain of mapping.
// Declare arbitrary string for each domain member.
// Provide type safety around declaration of the mapping.
// Provide data models and types useful for writing code with.
//
// I believe a typescript enum doesn't do this.
export const filterKeys = [
'Show All',
'Show Completed',
'Show Uncompleted',
] as const
export type FilterKeyType = typeof filterKeys[number]
export const filterLabels = {
'Show All': 'All',
'Show Completed': 'Completed',
'Show Uncompleted': 'Uncompleted',
} as const
export function validFilterOption(value: string): value is FilterKeyType {
return value in filterLabels
}
// Following just to enforce our type mapping isn't missing values.
type CheckMyKeyType = Array<keyof typeof filterLabels>[0]
// This variable is not used but I don't know how to check if types are Equal otherwise at moment.
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const myTypesEqual: EqualTypes<FilterKeyType, CheckMyKeyType> = true
import React, { useCallback } from 'react'
type Props<ValueType extends string> = {
label: string
isValidValue: (value: string) => value is ValueType
onChange: (value: ValueType) => void
thisOption: ValueType
value: ValueType
}
export default function RadioButton<ValueType extends string>({
label,
isValidValue,
onChange,
thisOption,
value,
}: Props<ValueType>) {
const eventOnChange = useCallback(
({ target: { value } }: React.ChangeEvent<HTMLInputElement>) => {
console.log('event target value', value)
if (isValidValue(value)) {
onChange(value)
} else {
throw new Error(
`RadioButton selected value "${value}" not found in ValueType`
)
}
},
[isValidValue, onChange]
)
return (
<label
title={label}
style={{
border: '1px #ddd solid',
backgroundColor: '#eee',
padding: '0.25rem',
borderRadius: '1rem',
userSelect: 'none', // disable select Chrome, opera
WebkitUserSelect: 'none', // disable select Safari
MozUserSelect: 'none', // disable select Safari
}}
>
<input
type="radio"
value={thisOption}
checked={value === thisOption}
onChange={eventOnChange}
/>
{label}
&nbsp;
</label>
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment