Represent maps
// rather than
const map: {[ key: string ]: string} = {
foo: 'bar',
}
// do
const map: Record<string, string|undefined> = {
foo: 'bar',
};
// ... or just do a Map
const map = new Map<string, string>()
const map = new Map([['foo', 'bar']])
<Formik
initialValues={initialValues}
enableReinitialize={true}
validate={(values) => {
const errors: Partial<typeof values> = {};
if (
values.contactEmail &&
!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.contactEmail)
) {
errors.contactEmail = 'Invalid email address';
}
return errors;
}}
// [..]
/>
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
Typecast return value of function
Unwrap the value of a promise.
export type ThenArg<TPromise> = TPromise extends PromiseLike<infer TValue>
? ThenArg<TValue>
: TPromise;
export type inferAsyncReturnType<TFunction extends (...args: any) => any> =
ThenArg<ReturnType<TFunction>>;
When making a wrapper of another react fn
export type MuiCreatableSelectProps = React.ComponentProps<
typeof CreatableSelect
> & {
label: string;
};
type OtherComponentProps = React.ComponentProps<
typeof OtherComponent
>;
export type MyComponentProps = Omit<OtherComponentProps, 'value' | 'otherValueNotNeeded'>;
export function MyComponent(props: MyComponent) {
// [..]
}
type Post = NonNullable<PostByIdQuery['Post_by_pk']>;
// Makes autocompletion works more reliably if you always do
export const MyComponent = () => { /* ... */ }
// instead of
export default () => { /* ... */ }
// bad
const fn = (arg1: string, arg2: string) => { /* ... */ }
// good
const fn = ({arg1, arg2}: {arg1: string, arg2: string}) => { /* ... */ }
type UseRemoteData =
| {
status: 'loading';
}
| {
status: 'error';
error: Error;
}
| {
status: 'ok';
result: RemoteDataResponse;
};
function useRemoteData(token: string): UseRemoteData {
const [result, setResult] = useState<UseRemoteData>({
status: 'loading',
});
useEffect(() => {
function load() {
doAsyncStuff()
.then((res) => {
setResult({
status: 'ok',
result: res,
});
})
.catch((error) => {
setResult({
status: 'error',
error,
});
});
}
load();
}, [token]);
return result;
}
I am currently enjoying to carry type information around using arrays with null values casted to the desired type.
They are basically only there to carry type information. I use these methods as sugar for something like
[ null as unknown as DesiredType] as const
These are the utilitypes I use for this.
Then I can define typetags like this
const SessionManagerTag = TypeTag<SessionManager>()
and use this as the key for deploying and resolving this object with correct typings like thisregistry.deploy( [ [ SessionManagerTag, new SessionManager(eventbus, stores) ] ] as const)
andconst [manager, session] = registry.discover([SessionManagerTag, UserSessionTag] as const)
The registry is very simple wrapper around a standard Map and is only there to resolve the typings correctly.