[Typescript] Write clean Type 3 - make a wrapper to cleanup generic usages

Original code:

import { CSSProperties } from "react";

const useStyled = <TTheme = {}>(func: (theme: TTheme) => CSSProperties) => {
  // Imagine that this function hooks into a global theme
  // and returns the CSSProperties
  return {} as CSSProperties;
};

interface MyTheme {
  color: {
    primary: string;
  };
  fontSize: {
    small: string;
  };
}

const buttonStyle = useStyled<MyTheme>((theme) => ({
  color: theme.color.primary,
  fontSize: theme.fontSize.small,
}));

const divStyle = useStyled<MyTheme>((theme) => ({
  backgroundColor: theme.color.primary,
}));

Notice that everytime we call useStyled<MyTheme>, we have to pass generic. We want a way that we don't need to pass generic.

 

Solution:

import { CSSProperties } from 'react';

const makeUseStyle = <TTheme = {}>() => {
  return (func: (theme: TTheme) => CSSProperties) => {
    return {} as CSSProperties;
  };
};
const useStyled = makeUseStyle<MyTheme>();

interface MyTheme {
  color: {
    primary: string;
  };
  fontSize: {
    small: string;
  };
}

const buttonStyle = useStyled((theme) => ({
  color: theme.color.primary,
  fontSize: theme.fontSize.small,
}));

const divStyle = useStyled((theme) => ({
  backgroundColor: theme.color.primary,
}));

Now when use call useStyle, we don't need to pass generic slot everytime.

This solution allows you to pass the generic once in the code and all the rest of code will get infer of those generic type.

 


 

Another example:

import { Equal, Expect } from '../helpers/type-utils';

export const makeSelectors =
  <TSource = 'TSource expects one arguement'>() =>
  <TSelectors extends Record<string, (source: TSource) => any>>(
    selectors: TSelectors
  ) => {
    return selectors;
  };

interface Source {
  firstName: string;
  middleName: string;
  lastName: string;
}

const useSelector = makeSelectors<Source>();

const selectors = useSelector({
  getFullName: (source) =>
    `${source.firstName} ${source.middleName} ${source.lastName}`,
  getFirstAndLastName: (source) => `${source.firstName} ${source.lastName}`,
  getFirstNameLength: (source) => source.firstName.length,
});

type tests = [
  Expect<Equal<typeof selectors['getFullName'], (source: Source) => string>>,
  Expect<
    Equal<typeof selectors['getFirstAndLastName'], (source: Source) => string>
  >,
  Expect<
    Equal<typeof selectors['getFirstNameLength'], (source: Source) => number>
  >
];

 

posted @ 2023-04-17 14:45  Zhentiw  阅读(15)  评论(0编辑  收藏  举报