Skip to content

Commit

Permalink
🐛 fix: 修正 createStyles 的类型定义,避免无法正常跳转
Browse files Browse the repository at this point in the history
  • Loading branch information
arvinxx committed Jan 8, 2023
1 parent 2002aff commit 4bef457
Show file tree
Hide file tree
Showing 6 changed files with 169 additions and 27 deletions.
8 changes: 3 additions & 5 deletions src/functions/createStyish.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import { createStyles, CssStyleOrGetCssStyleFn } from './createStyles';
import { createStyles, ReturnStyleToUse, StyleOrGetStyleFn } from './createStyles';

/**
* 业务应用中创建复合通用样式的进阶
*/
export function createStylish<Props, Key extends string>(
cssStyleOrGetCssStyleFn: CssStyleOrGetCssStyleFn<Props, Key>,
) {
export function createStylish<Props, Obj>(cssStyleOrGetCssStyleFn: StyleOrGetStyleFn<Props, Obj>) {
const useStyles = createStyles(cssStyleOrGetCssStyleFn);

return (props?: Props): Record<Key, string> => {
return (props?: Props): ReturnStyleToUse<Obj> => {
const { styles } = useStyles(props);

return styles;
Expand Down
46 changes: 24 additions & 22 deletions src/functions/createStyles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { Emotion } from '@emotion/css/create-instance';
import { useMemo } from 'react';

import { useTheme } from '@/hooks';
import { AntdStylish, FullToken, Theme } from '@/types';
import { AntdStylish, FullToken, ReturnStyleToUse, StyleDefinition, Theme } from '@/types';

export interface CreateStylesTheme {
token: FullToken;
Expand All @@ -12,37 +12,40 @@ export interface CreateStylesTheme {
css: Emotion['css'];
}

export type StyleParams<T extends string> = string | Record<T, CSSObject | string>;

export type CssStyleOrGetCssStyleFn<Props, Key extends string> =
| StyleParams<Key>
| ((theme: CreateStylesTheme, props?: Props) => StyleParams<Key>);

export interface ReturnStyles<Key extends string> {
styles: Record<Key, string>;
/**
* 最终返回 styles 对象的类型定义
*/
export interface ReturnStyles<Obj> {
styles: ReturnStyleToUse<Obj>;
theme: Theme;
cx: Emotion['cx'];
}

/**
* 创建样式的函数或者对象
*/
export type StyleOrGetStyleFn<P, S> =
| StyleDefinition<S>
| ((theme: CreateStylesTheme, props?: P) => StyleDefinition<S>);

/**
* 业务应用中创建样式基础写法
*/
export function createStyles<Props, Key extends string>(
cssStyleOrGetCssStyleFn: CssStyleOrGetCssStyleFn<Props, Key>,
) {
return (props?: Props): ReturnStyles<Key> => {
export function createStyles<Props, Obj>(styleOrGetStyleFn: StyleOrGetStyleFn<Props, Obj>) {
return (props?: Props) => {
const theme = useTheme();

return useMemo(() => {
let styles: Record<Key, string>;
// FIXME:如何收敛类型? How to fix types?
// @ts-ignore
return useMemo<ReturnStyles<Obj>>(() => {
let styles;

if (typeof cssStyleOrGetCssStyleFn === 'function') {
if (styleOrGetStyleFn instanceof Function) {
const { stylish, ...token } = theme;
// @ts-ignore
styles = cssStyleOrGetCssStyleFn({ token, stylish, cx, css }, props);

styles = styleOrGetStyleFn({ token, stylish, cx, css }, props);
} else {
// @ts-ignore
styles = cssStyleOrGetCssStyleFn;
styles = styleOrGetStyleFn;
}

if (typeof styles === 'object') {
Expand All @@ -54,9 +57,8 @@ export function createStyles<Props, Key extends string>(

return [key, value];
}),
) as Record<Key, string>;
);
}
// 处理

return {
styles,
Expand Down
22 changes: 22 additions & 0 deletions src/types/genericUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { CSSObject } from '@emotion/css';

/**
* 给用户提供类型定义的返回签名
* 用户可以使用 key: css` color:red `,或者 key :{ color : 'red' },都能正常提供类型定义
*/
export type StyleDefinition<StyleObj> = StyleObj extends string
? string
: Record<keyof StyleObj, CSSObject | string>;

// type IsString<T> = T extends string ? true : false;
// export type ReturnStyleToUse<T> = IsString<T> extends true
// ? string
// : T extends Record<infer R, any>
// ? Record<R, string>
// : never;
/**
* 根据用户返回的样式对象,返回一个可以给用户使用的
* 譬如用户输入为 { a: css`color: red;`, b: { color: 'red' }
* 输出的类型泛型为 { a:string; b:string }
*/
export type ReturnStyleToUse<T> = T extends Record<infer R, any> ? Record<R, string> : string;
1 change: 1 addition & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './appearance';
export * from './css';
export * from './genericUtils';
export * from './styled';
export * from './theme';
47 changes: 47 additions & 0 deletions tests/functions/__snapshots__/createStyles.test.tsx.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`createStyles styles 对象的使用 createStyleFn 通过函数方式可以拿到 token 等信息 TODO: 只返回一个 css 字符串,使用正常,类型定义也正常 1`] = `
.emotion-0 {
background-color: #f5f5f5;
padding: 24px;
}
<div
class="emotion-0"
>
card
</div>
`;

exports[`createStyles styles 对象的使用 createStyleFn 通过函数方式可以拿到 token 等信息 字符串模板的对象模式用法 1`] = `
.emotion-0 {
background-color: #f5f5f5;
Expand All @@ -21,6 +34,40 @@ exports[`createStyles styles 对象的使用 createStyleFn 通过函数方式可
</div>
`;

exports[`createStyles styles 对象的使用 styleObject 方法 css模式的写法 1`] = `
.emotion-0 {
background-color: #f5f5f5;
padding: 24px;
}
.emotion-1 {
margin-top: 16px;
}
<div
class="emotion-0"
>
<div
class="emotion-1"
>
card
</div>
</div>
`;

exports[`createStyles styles 对象的使用 styleObject 方法 只返回一个 css 字符串,使用正常,类型定义也正常 1`] = `
.emotion-0 {
background-color: #f5f5f5;
padding: 24px;
}
<div
class="emotion-0"
>
card
</div>
`;

exports[`createStyles styles 对象的使用 styleObject 方法 对象模式的用法 1`] = `
.emotion-0 {
background-color: #f5f5f5;
Expand Down
72 changes: 72 additions & 0 deletions tests/functions/createStyles.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,35 @@ describe('createStyles', () => {
expect(container.firstChild).toHaveStyle({ backgroundColor: '#f5f5f5' });
});

it('TODO: 只返回一个 css 字符串,使用正常,类型定义也正常', () => {
const useStyles = createStyles(
// FIXME:类型定义不正常
// @ts-ignore
({ token }) => css`
background-color: ${token.colorBgLayout};
padding: 24px;
`,
);

const App = () => {
const { styles } = useStyles();

return <div className={styles}>card</div>;
};

const { container } = render(<App />);

expect(container.firstChild).toMatchSnapshot();
expect(container.firstChild).toHaveStyle({ backgroundColor: '#f5f5f5' });
});

it.skip('TODO: 对象模式的用法,可以不包含 css,类型定义与提示正常,使用也正常', () => {
const useStyles = createStyles(({ token }) => ({
container: `
background-color: ${token.colorBgLayout};
padding: 24px;
`,

card: `
margin-top: ${token.marginLG}px;
`,
Expand Down Expand Up @@ -85,6 +108,55 @@ describe('createStyles', () => {
expect(container.firstChild).toMatchSnapshot();
expect(container.firstChild).toHaveStyle({ backgroundColor: '#f5f5f5' });
});

it('css模式的写法', () => {
const useStyles = createStyles({
container: css`
background-color: #f5f5f5;
padding: 24px;
`,
card: css`
margin-top: 16px;
`,
});

const App = () => {
const { styles } = useStyles();
return (
<div className={styles.container}>
<div className={styles.card}>card</div>
</div>
);
};

const { container } = render(<App />);

expect(container.firstChild).toMatchSnapshot();
expect(container.firstChild).toHaveStyle({ backgroundColor: '#f5f5f5' });
});

it('只返回一个 css 字符串,使用正常,类型定义也正常', () => {
const useStyles = createStyles(
// FIXME:类型定义不正常
// @ts-ignore
css`
background-color: #f5f5f5;
padding: 24px;
`,
);

const App = () => {
const { styles } = useStyles();
// FIXME:类型定义不正常
// @ts-ignore
return <div className={styles}>card</div>;
};

const { container } = render(<App />);

expect(container.firstChild).toMatchSnapshot();
expect(container.firstChild).toHaveStyle({ backgroundColor: '#f5f5f5' });
});
});
});

Expand Down

0 comments on commit 4bef457

Please sign in to comment.