-
Notifications
You must be signed in to change notification settings - Fork 135
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve TypeSafety #16
Changes from 11 commits
d67f459
3bb338d
f901f00
1ddc915
382fbdd
d3af8bc
c09dd1b
436a67e
730deb8
c72487d
4a48eaa
5da7874
eb862e3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,3 +6,6 @@ npm-debug.log | |
.jest | ||
|
||
dist | ||
|
||
# IDE | ||
.idea |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,11 +5,10 @@ import { | |
RestyleFunctionContainer, | ||
} from './types'; | ||
|
||
type StyleTransformFunction = (params: { | ||
value: any; | ||
theme: BaseTheme; | ||
themeKey?: string; | ||
}) => any; | ||
type StyleTransformFunction< | ||
Theme extends BaseTheme, | ||
K extends keyof Theme | undefined | ||
> = (params: {value: any; theme: Theme; themeKey?: K}) => any; | ||
|
||
const getValueForScreenSize = ({ | ||
responsiveValue, | ||
|
@@ -41,20 +40,29 @@ const isResponsiveObjectValue = <Theme extends BaseTheme>( | |
}, true); | ||
}; | ||
|
||
const getValue = <Theme extends BaseTheme>( | ||
propValue: ResponsiveValue<string | number, Theme>, | ||
type PropValue = string | number | undefined | null; | ||
|
||
function isThemeKey<Theme extends BaseTheme>( | ||
theme: Theme, | ||
K: keyof Theme | undefined, | ||
): K is keyof Theme { | ||
return theme[K as keyof Theme]; | ||
} | ||
|
||
const getValue = <Theme extends BaseTheme, K extends keyof Theme | undefined>( | ||
propValue: ResponsiveValue<PropValue, Theme>, | ||
{ | ||
theme, | ||
transform, | ||
dimensions, | ||
themeKey, | ||
}: { | ||
theme: Theme; | ||
transform?: StyleTransformFunction; | ||
transform?: StyleTransformFunction<Theme, K>; | ||
dimensions: Dimensions; | ||
themeKey?: string; | ||
themeKey?: K; | ||
}, | ||
) => { | ||
): PropValue => { | ||
const val = isResponsiveObjectValue(propValue, theme) | ||
? getValueForScreenSize({ | ||
responsiveValue: propValue, | ||
|
@@ -63,7 +71,7 @@ const getValue = <Theme extends BaseTheme>( | |
}) | ||
: propValue; | ||
if (transform) return transform({value: val, theme, themeKey}); | ||
if (themeKey && theme[themeKey]) { | ||
if (isThemeKey(theme, themeKey)) { | ||
if (val && theme[themeKey][val] === undefined) | ||
throw new Error(`Value '${val}' does not exist in theme['${themeKey}']`); | ||
|
||
|
@@ -73,26 +81,28 @@ const getValue = <Theme extends BaseTheme>( | |
return val; | ||
}; | ||
|
||
const createRestyleFunction = ({ | ||
const createRestyleFunction = < | ||
Theme extends BaseTheme = BaseTheme, | ||
TProps extends Record<string, unknown> = Record<string, unknown>, | ||
P extends keyof TProps = keyof TProps, | ||
K extends keyof Theme | undefined = undefined | ||
>({ | ||
property, | ||
transform, | ||
styleProperty = property, | ||
styleProperty = property.toString(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. since objects can have numbered or Symbol properties, but the styleProperty type is a string, we need to convert it to a string if we want to assign it like this by default. |
||
themeKey, | ||
}: { | ||
property: string; | ||
transform?: StyleTransformFunction; | ||
property: P; | ||
transform?: StyleTransformFunction<Theme, K>; | ||
styleProperty?: string; | ||
themeKey?: string; | ||
}): RestyleFunctionContainer => { | ||
themeKey?: K; | ||
}): RestyleFunctionContainer<TProps, Theme, P, K> => { | ||
return { | ||
property, | ||
themeKey, | ||
variant: false, | ||
func: ( | ||
props: any, | ||
{theme, dimensions}: {theme: BaseTheme; dimensions: Dimensions}, | ||
): {[key: string]: any} => { | ||
const value = getValue(props[property], { | ||
func: (props, {theme, dimensions}) => { | ||
const value = getValue(props[property] as PropValue, { | ||
theme, | ||
dimensions, | ||
themeKey, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 +1,25 @@ | ||
import { | ||
BaseTheme, | ||
Dimensions, | ||
RestyleFunctionContainer, | ||
ResponsiveValue, | ||
} from './types'; | ||
import {BaseTheme, RestyleFunctionContainer, ResponsiveValue} from './types'; | ||
import createRestyleFunction from './createRestyleFunction'; | ||
import {all, AllProps} from './restyleFunctions'; | ||
import composeRestyleFunctions from './composeRestyleFunctions'; | ||
|
||
const allRestyleFunctions = composeRestyleFunctions(all); | ||
|
||
const createVariant = <Theme extends BaseTheme = BaseTheme>({ | ||
property = 'variant', | ||
const createVariant = < | ||
Theme extends BaseTheme, | ||
TProps extends VariantProps<Theme, K, P> = VariantProps<Theme, keyof Theme>, | ||
P extends keyof TProps | 'variant' = 'variant', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @JoelBesada Just pushed some changes giving createVariant some 🔥 type safety and inference. Try it out and let me know how it works. Stress test it with custom properties and PropTypes and themes, etc. It should be able to pick up any incorrect setup no matter how/where it's used. It works best when defined inline with createRestyleComponent/useRestyle, etc, but it still works when its not. |
||
K extends keyof Theme = keyof Theme | ||
>({ | ||
property = 'variant' as P, | ||
themeKey, | ||
defaults = {}, | ||
}: { | ||
property?: string; | ||
themeKey: string; | ||
property?: P; | ||
themeKey: K; | ||
defaults?: AllProps<Theme>; | ||
}): RestyleFunctionContainer => { | ||
const styleFunction = createRestyleFunction({ | ||
}): RestyleFunctionContainer<TProps, Theme> => { | ||
const styleFunction = createRestyleFunction<Theme, TProps, P, K>({ | ||
property, | ||
styleProperty: 'expandedProps', | ||
themeKey, | ||
|
@@ -28,10 +28,7 @@ const createVariant = <Theme extends BaseTheme = BaseTheme>({ | |
property, | ||
themeKey, | ||
variant: true, | ||
func: ( | ||
props: any, | ||
{theme, dimensions}: {theme: BaseTheme; dimensions: Dimensions}, | ||
) => { | ||
func: (props, {theme, dimensions}) => { | ||
const {expandedProps} = styleFunction.func(props, {theme, dimensions}); | ||
if (!expandedProps) return {}; | ||
return allRestyleFunctions.buildStyle( | ||
|
@@ -47,8 +44,8 @@ const createVariant = <Theme extends BaseTheme = BaseTheme>({ | |
|
||
export type VariantProps< | ||
Theme extends BaseTheme, | ||
ThemeKey extends keyof Theme, | ||
Property extends string = 'variant' | ||
> = {[key in Property]?: ResponsiveValue<keyof Theme[ThemeKey], Theme>}; | ||
K extends keyof Theme, | ||
Property extends keyof any = 'variant' | ||
> = {[key in Property]?: ResponsiveValue<keyof Theme[K], Theme>}; | ||
|
||
export default createVariant; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a valid case for when you should be able to override P and K here? If not, I would prefer to just using
keyof TProps
andkeyof Theme
inline within the function.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Its not so much about overriding as it is about having a strongly typed return type so that the exact property and themeKey the user specified is preserved and carried through to anything consuming that restyle function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah right, got it