-
-
Save slackday/7142251cf2bb3660f8c24492aa1f700d to your computer and use it in GitHub Desktop.
// Project 1: | |
// Styled componet wrapper might look like this | |
const styledFactory = ( | |
target: any, | |
displayName: string, | |
...systemFunctions: styleFn[] | |
): any => { | |
const Component = styled(target)` | |
min-width: 0; | |
${sx} | |
${compose(animation, color, flexbox, layout, space, ...systemFunctions)} | |
`; | |
Component.displayName = displayName; | |
return Component; | |
}; | |
//----- | |
// Project 2 tries to use same function but with Typescript | |
// But with typescript lint rule "no-explicit-any" | |
// Disallow usage of the any type | |
// https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-explicit-any.md | |
// Same component becomes wild goose chase of finding the right types for dependencies | |
const styledFactory = ( | |
target: AnyStyledComponent, | |
displayName: string, | |
...systemFunctions: ThemedStyledFunction[] | |
): AnyStyledComponent => { | |
const Component = styled(target)` | |
min-width: 0; | |
${sx} | |
${compose(animation, color, flexbox, layout, space, ...systemFunctions)} | |
`; | |
Component.displayName = displayName; | |
return Component; | |
}; |
A more advanced trick for the HOC case is the ReturnType<T>
generic option, where you use Typescript's inferencing engine directly in finding out what the return type of something else is.
const styledFactory = (
target: AnyStyledComponent,
displayName: string,
...systemFunctions: ThemedStyledFunction[]
): ReturnType<typeof styled> => {
const Component = styled(target)`
min-width: 0;
${sx}
${compose(animation, color, flexbox, layout, space, ...systemFunctions)}
`;
Component.displayName = displayName;
return Component;
};
Because you are simply returning what styled()
itself returns, you can ask Typescript for the ReturnType
of (the typeof
) that function.
Hey Max thanks a lot for taking your time providing me with thorough examples. It's all starting to make much more sense to me. Not to get stuck on lint errors so it's a good idea to document Todo and come back to it later.
I really like the generic return type option. Thinking about it. This probably solves 9/10 issues I have had in the past. Often the use case is just to return whatever the underlying method returns (in the dependency). And this approach seems like the appropriate way of handling it in a clean way 💯 👍
I also got the tips on hackernews to look into *.d.ts
files which I was unaware of. Again thanks!
React HOCs are tough to type. One theoretical benefit to Hooks is hopefully less need for HOCs like that styled-component factory.
One thing I find useful to note is that
no-implicit-any
doesn't stop you from using an explicitany
. Don't fear usingany
as an escape valve just becauseno-implicit-any
even when following the good advice tono-implicit-any
, just do it explicitly (and then you can search forany
as a TODO list when you do find or need to find a better type) and/or include a TODO comment next to it as well.For instance:
As for your second example, remember that because you are calling
window.document
you are escaping out of the React world back to the old world DOM. In that case you aren't using one of React's synthetic events, but an old fashioned DOM event and it is just calledMouseEvent
(notReact.MouseEvent
). In that case, you can use Typescript's own power to help you find that out. If you hover over theaddEventListener('click',
function name in most IDEs you should see that type information it expects for its callback argument. (Something neat there is that Typescript is smart enough to know based on that first string argument exactly which type.)