如何根据当前函数参数在Typescript中使返回函数的参数成为必需或非必需的?

huangapple go评论70阅读模式
英文:

How to make the parameters of returning function required or not based on current function parameters Typescript?

问题

以下是代码的中文翻译部分:

const createStyledComponent = (
	type: any,
	component_style: CSSProperties | undefined,
	children?: boolean
) => {
	if (children) {
		const returnComponent = ({
			children,
			style,
		}: {
			children: any;
			style?: CSSProperties | undefined;
		}) => {
			return React.createElement(
				type,
				{ style: { ...component_style, ...style } },
				children
			);
		};
		return returnComponent;
	} else {
		const returnComponent = ({
			children,
			style,
		}: {
			children?: any;
			style?: CSSProperties | undefined;
		}) => {
			return React.createElement(
				type,
				{ style: { ...component_style, ...style } },
				children
			);
		};
		return returnComponent;
	}
};
英文:

I am new to Typescript and trying to mimic styled-components at a much lower scale. In my case, I want to make children required if user passed true in createStyledComponent for children parameter, otherwise make the children optional.

I kinda have a newbie solution to my problem where I am returning 2 different functionsm, one with required children and other with optional.

Is there a better and concise way to do this task?

const createStyledComponent = (
	type: any,
	component_style: CSSProperties | undefined,
	children?: boolean
) => {
	if (children) {
		const returnComponent = ({
			children,
			style,
		}: {
			children: any;
			style?: CSSProperties | undefined;
		}) => {
			return React.createElement(
				type,
				{ style: { ...component_style, ...style } },
				children
			);
		};
		return returnComponent;
	} else {
		const returnComponent = ({
			children,
			style,
		}: {
			children?: any;
			style?: CSSProperties | undefined;
		}) => {
			return React.createElement(
				type,
				{ style: { ...component_style, ...style } },
				children
			);
		};
		return returnComponent;
	}
};

答案1

得分: 1

I would probably try and take a stab at generics honestly. 以下是可能适用于您的用例的示例代码。

type StyledProps<C extends boolean> = {
    style?: CSSProperties;
    children: C extends true ? ReactNode : ReactNode | undefined;
};

const createStyledComponent = <C extends boolean>(
    type: any,
    component_style?: CSSProperties,
    childrenRequired: C = false as C
) => {
    const returnComponent = ({ children, style }: StyledProps<C>) => {
        return React.createElement(
            type,
            { style: { ...component_style, ...style } },
            children
        );
    };
    return returnComponent;
};

But your implementation details might vary. I definitely would stray away from big if, else render blocks that are largely the same. In that type of scenario it can be helpful to abstract these blocks into separate components, or do inline conditionals.

return (
    <div>
        {/* other shared render logic */}
        {value === true && (
            <div>value true render</div>
        )}
        {value === false && (
            <div>value false render</div>
        )}
    </div>
)

Good luck!

英文:

I would probably try and take a stab at generics honestly. https://www.typescriptlang.org/docs/handbook/2/generics.html

Something like the following might work for your use case.

type StyledProps&lt;C extends boolean&gt; = {
    style?: CSSProperties;
    children: C extends true ? ReactNode : ReactNode | undefined;
};

const createStyledComponent = &lt;C extends boolean&gt;(
    type: any,
    component_style?: CSSProperties,
    childrenRequired: C = false as C
) =&gt; {
    const returnComponent = ({ children, style }: StyledProps&lt;C&gt;) =&gt; {
        return React.createElement(
            type,
            { style: { ...component_style, ...style } },
            children
        );
    };
    return returnComponent;
};

But your implementation details might vary. I definitely would stray away from big if, else render blocks that are largely the same. In that type of scenario it can be helpful to abstract these blocks into separate components, or do inline conditionals

return (
    &lt;div&gt;
        {/* other shared render logic */}
        {value === true &amp;&amp; (
            &lt;div&gt;value true render&lt;/div&gt;
        )}
        {value === false &amp;&amp; (
            &lt;div&gt;value false render&lt;/div&gt;
        )}
    &lt;/div&gt;
)

Good luck!

答案2

得分: 0

以下是翻译好的内容:

你想要函数重载


这里有两个签名:

一个要求children

function createStyledComponent(
  type: any,
  component_style: CSSProperties | undefined,
  children: true, // 明确为true
): (
  props: { children: React.ReactNode, style?: CSSProperties }
) => React.ReactNode

另一个不需要children

function createStyledComponent(
  type: any,
  component_style: CSSProperties | undefined,
  children?: false // 缺失或明确为false
): (
  props: { children?: React.ReactNode, style?: CSSProperties }
) => React.ReactNode

然后,你可以编写实现如下:

function createStyledComponent(
    type: any,
    component_style: CSSProperties | undefined,
    // 这里的children参数实际上不是必需的,
    // 因为实现是相同的
): (
  props: { children?: React.ReactNode, style?: CSSProperties }
) => React.ReactNode {
    const returnComponent = ({
        children,
        style,
    }: {
        children?: React.ReactNode;
        style?: CSSProperties | undefined;
    }) => {
        return React.createElement(
            type,
            { style: { ...component_style, ...style } },
            children
        );
    };
    return returnComponent;
};

注意,你函数的children参数在实现中已经消失了。在运行时它没有用,因为逻辑是相同的,但它确实可以让我们向类型系统提供提示并强制执行所需的内容。

现在来测试一下:

createStyledComponent('div', undefined)({}) // 正常
createStyledComponent('div', undefined)({ children: <></> }) // 正常

createStyledComponent('div', undefined, true)({ children: <></> }) // 正常
createStyledComponent('div', undefined, true)({}) // 预期错误,没有children

查看示例

英文:

You want function overloads.


You have two signatures here:

One where children are required:

function createStyledComponent(
  type: any,
  component_style: CSSProperties | undefined,
  children: true, // explicit true
): (
  props: { children: React.ReactNode, style?: CSSProperties }
) =&gt; React.ReactNode

And one where they are not:

function createStyledComponent(
  type: any,
  component_style: CSSProperties | undefined,
  children?: false // missing or explicit false
): (
  props: { children?: React.ReactNode, style?: CSSProperties }
) =&gt; React.ReactNode

Then you can write the implementation as follows:

function createStyledComponent(
    type: any,
    component_style: CSSProperties | undefined,
    // children parameter here is not actually required,
    // since the implementation is identical
): (
  props: { children?: React.ReactNode, style?: CSSProperties }
) =&gt; React.ReactNode {
    const returnComponent = ({
        children,
        style,
    }: {
        children?: React.ReactNode;
        style?: CSSProperties | undefined;
    }) =&gt; {
        return React.createElement(
            type,
            { style: { ...component_style, ...style } },
            children
        );
    };
    return returnComponent;
};

Note that the children parameter to your function is gone in the implementation. It has no use at runtime since the logic is identical, but it does allows us to give the type system a tip and enforce what is required.

Now to test that out:

createStyledComponent(&#39;div&#39;, undefined)({}) // fine
createStyledComponent(&#39;div&#39;, undefined)({ children: &lt;&gt;&lt;/&gt; }) // fine

createStyledComponent(&#39;div&#39;, undefined, true)({ children: &lt;&gt;&lt;/&gt; }) // fine
createStyledComponent(&#39;div&#39;, undefined, true)({}) // error as expected, no children

See playground

huangapple
  • 本文由 发表于 2023年5月26日 00:24:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/76334426.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定