Skip to content

Commit

Permalink
fix: easier and more precise polymorphic typing
Browse files Browse the repository at this point in the history
  • Loading branch information
michalkvasnicak committed Feb 12, 2021
1 parent 916cd88 commit 84ae0f9
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 321 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module.exports = {
},
extends: ['airbnb-typescript-prettier'],
rules: {
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/no-empty-interface': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
Expand Down
9 changes: 6 additions & 3 deletions packages/visage-core/src/__tests__/typeTest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
import React from 'react';
import { createComponent } from '../createComponent';
import { VisageComponent } from '../types';
import { StyleSheet } from '../styleSheet';

const Div = createComponent('div');

<Div />;

declare function FC(p: { test: boolean }): JSX.Element;

Expand Down Expand Up @@ -191,8 +194,8 @@ const AssignComplexMemoAndForward: VisageComponent<
> = React.memo(
React.forwardRef(
(
props: JSX.IntrinsicElements['h1'] & { test: boolean },
ref: React.Ref<HTMLHeadingElement>,
props: JSX.IntrinsicElements['div'] & { test: boolean },
ref: React.Ref<HTMLDivElement>,
) => null,
),
);
Expand Down
16 changes: 5 additions & 11 deletions packages/visage-core/src/createComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,11 @@ const DEFAULT_STYLE_SHEET = {};
*/
export function createComponent<
TDefaultComponent extends ComponentConstraint,
TVariants extends Record<string, any>[] = Record<string, any>[],
TVariantIntersection = UnionToIntersection<TVariants[number]>,
TProps extends Omit<
ExtractVisageComponentProps<TDefaultComponent>,
keyof TVariantIntersection
> &
TVariantIntersection = Omit<
ExtractVisageComponentProps<TDefaultComponent>,
keyof TVariantIntersection
> &
TVariantIntersection,
TVariants extends undefined | Record<string, unknown>[] = undefined,
TProps = TVariants extends Record<string, unknown>[]
? ExtractVisageComponentProps<TDefaultComponent> &
UnionToIntersection<TVariants[number]>
: ExtractVisageComponentProps<TDefaultComponent>,
TDefaultProps extends Partial<TProps> = any
>(
defaultAs: TDefaultComponent,
Expand Down
275 changes: 24 additions & 251 deletions packages/visage-core/src/types.ts

Large diffs are not rendered by default.

5 changes: 2 additions & 3 deletions packages/visage-core/src/useStaticMemo.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { useMemo } from 'react';
import { ExtractArgs, ExtractReturn } from './types';

/**
* Uses statically declared function in useMemo
Expand All @@ -8,8 +7,8 @@ import { ExtractArgs, ExtractReturn } from './types';
*/
export function useStaticMemo<TFunction extends (...args: any[]) => any>(
fn: TFunction,
deps: ExtractArgs<TFunction>,
): ExtractReturn<TFunction> {
deps: Parameters<TFunction>,
): ReturnType<TFunction> {
// eslint-disable-next-line react-hooks/exhaustive-deps
return useMemo(() => fn(...deps), deps);
}
86 changes: 37 additions & 49 deletions packages/visage/src/components/Heading.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,43 +103,38 @@ export interface HeadingProps extends H1Props {

export const Heading = markAsVisageComponent(
memo(
forwardRef(
(
{ level = 1, ...restProps }: JSX.IntrinsicElements['h1'] & HeadingProps,
ref: any,
) => {
let as = h1;

switch (level) {
case 2:
as = h2;
break;
case 3:
as = h3;
break;
case 4:
as = h4;
break;
case 5:
as = h5;
break;
case 6:
as = h6;
}

return createElement(as, {
ref,
// @ts-ignore
'data-level': level,
...restProps,
});
},
),
forwardRef<HTMLHeadingElement, HeadingProps>(function Heading(
{ level = 1, ...restProps }: HeadingProps,
ref,
) {
let as = h1;

switch (level) {
case 2:
as = h2;
break;
case 3:
as = h3;
break;
case 4:
as = h4;
break;
case 5:
as = h5;
break;
case 6:
as = h6;
}

return createElement(as, {
ref,
'data-level': level,
...restProps,
});
}),
),
);

Heading.displayName = 'Heading';

const defaultMask = [6];

interface HeadingSkeletonProps {
Expand All @@ -151,20 +146,13 @@ interface HeadingSkeletonProps {

export const HeadingSkeleton = markAsVisageComponent(
memo(
forwardRef(
(
{
mask = defaultMask,
...restProps
}: JSX.IntrinsicElements['h1'] & HeadingProps & HeadingSkeletonProps,
ref: any,
) => {
return (
<Heading as={SkeletonSentence} mask={mask} ref={ref} {...restProps} />
);
},
),
forwardRef<
HTMLDivElement,
Omit<HeadingProps & HeadingSkeletonProps, 'ref'>
>(function HeadingSkeleton({ mask = defaultMask, ...restProps }, ref) {
return (
<Heading as={SkeletonSentence} mask={mask} ref={ref} {...restProps} />
);
}),
),
);

HeadingSkeleton.displayName = 'HeadingSkeleton';
3 changes: 1 addition & 2 deletions packages/visage/src/hooks/useOnRenderEffect.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { useEffect, useMemo } from 'react';
import { ExtractArgs } from '@byteclaw/visage-core';

/**
* Works similarly as useEffect except it runs effect before children are rendered
Expand Down Expand Up @@ -27,7 +26,7 @@ export function useOnRenderEffect(
*/
export function useStaticOnRenderEffect<
T extends (...effectArgs: any[]) => void | (() => void)
>(effect: T, ...args: ExtractArgs<T>): void {
>(effect: T, ...args: Parameters<T>): void {
// eslint-disable-next-line react-hooks/exhaustive-deps
const unregister = useMemo(() => effect(...args), [effect, ...args]);

Expand Down
3 changes: 1 addition & 2 deletions packages/visage/src/hooks/useStaticEffect.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { ExtractArgs } from '@byteclaw/visage-core';
import { useEffect } from 'react';

/**
* Creates a static effect that is called with provided args
*/
export function useStaticEffect<T extends (...effectArgs: any[]) => void>(
effectFn: T,
...args: ExtractArgs<T>
...args: Parameters<T>
): void {
useEffect(() => {
return effectFn(...args);
Expand Down

0 comments on commit 84ae0f9

Please sign in to comment.