如何在Zod中创建模式以验证React元素

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

How to create schema to validate react element in zod

问题

在这种情况下,我想要将只有 React 组件作为输入。

import { FC, ReactElement } from 'react';
import { NextLink } from '../links/NextLink';
import { z } from 'zod';
export const BlogCard2PropsSchema = z.object({
  link: z.string(),
  title: z.string(),

  category: z.string(),
  description: z.string(),
  cardTop: ReactElement
});

有没有办法正确地为 cardTop 属性添加类型,而不需要使用 ? ?

英文:

In this scenario, i want to take only a react component as input.

import { FC, ReactElement } from 'react';
import { NextLink } from '../links/NextLink';
import { z } from 'zod';
export const BlogCard2PropsSchema = z.object({
  link: z.string(),
  title: z.string(),

  category: z.string(),
  description: z.string(),
  cardTop: ReactElement
});

Is there any way to type the cardTop Property Properly, without any ?

答案1

得分: 1

根据我了解,Zod 用于数据。它非常适用于定义数据模型,例如前端模型,比如用户对象,或后端模型,比如数据库表格(似乎与 kysley 配合得很好)。

因此,我认为在视图层上使用纯TS/React类型更加简单,因为在这方面 Zod 似乎有些不足,而且对于应用程序而言太冗长。

Zod 可能是故意设计成这样的,但我找不到相关文章。但从根本上讲,数据应该与视图分离,数据类型应该强大,视图类型应该相对简单(例如 ReactNode),而视图层的类型层次结构(强弱程度)应该在 React 节点的视图布局中定义。

type AppPropsType = {
  page: React.ReactNode,
  name: string,
}

这对于视图层来说更加清晰和足够强大。数据层将受益于 Zod。

免责声明:这只是理论,但代码是有道理的。唯一的真正不足之处是,当你拥有非 ReactNode 类型时,比如字符串,你本能地想要使用 z.string,但如果你将它更改为 z.object,你就无法再在其中使用 ReactNode。因此,这个不足是双向的。

Zod 可能需要类似于 ReactNode 的东西,也许可以同样适用于 Angular,或者进行分离处理。

英文:

As far as I can tell, zod is for data. It works well for typing Data Models, such as frontend models like a user object or a backend object like a database table (seems to work well with kysley).

As a result, I have determined its far easier to use pure TS/React typing on the View Layer, where zod seems quite deficient and too verbose for the application.

Zod might be designed this way intentionally, but I couldn't and article on it. But fundamentally Data should be separate from Views, data typing is strong, view typing is pretty simple (e.g. ReactNode) and really the type hierarchy (strongeness) is defined in the View Layout for react nodes.

type AppPropsType = {
  page: React.ReactNode,
  name: string,
}

It is much cleaner and strong enough typing for the View Layer. Data layer will benefit from zod.

Disclaimer: Theoretical, but code makes sense. The only real deficiency is that when you have non-ReactNode types, like string, you inherently want to use z.string... but if you change it to a z.object you can no longer user ReactNode in it. SO the deficiency goes both ways.

Zod should get something equivalent to ReactNode, perhaps that works equally well for Angular or perhaps segregated.

答案2

得分: 0

import { FC } from 'react';

type ReactComponent<P = {}> = FC<P> & {
  defaultProps?: Partial<P>;
}

This ReactComponent 类型定义了一个泛型类型参数 P,可以用于定义组件的 props。

import { z } from 'zod';
import { ReactComponent } from './types';

export const BlogCard2PropsSchema = z.object({
  link: z.string(),
  title: z.string(),

  category: z.string(),
  description: z.string(),
  cardTop: z.function<ReactComponent>({ })
});
英文:
import { FC } from &#39;react&#39;;

type ReactComponent&lt;P = {}&gt; = FC&lt;P&gt; &amp; {
  defaultProps?: Partial&lt;P&gt;;
}

This ReactComponent type defines a generic type parameter P that can be used to define the props of the component.

import { z } from &#39;zod&#39;;
import { ReactComponent } from &#39;./types&#39;;

export const BlogCard2PropsSchema = z.object({
  link: z.string(),
  title: z.string(),

  category: z.string(),
  description: z.string(),
  cardTop: z.function&lt;ReactComponent&gt;({ })
});

答案3

得分: 0

你可以使用最适合你的情况的自定义函数:

import { FC, ReactNode } from 'react';
import { NextLink } from '../links/NextLink';
import { z } from 'zod';
export const BlogCard2PropsSchema = z.object({
  link: z.string(),
  title: z.string(),
  category: z.string(),
  description: z.string(),
  cardTop: z.custom<ReactNode>()
});
英文:

You can use the custom function that is the most suitable for your case:

import { FC, ReactNode } from &#39;react&#39;;
import { NextLink } from &#39;../links/NextLink&#39;;
import { z } from &#39;zod&#39;;
export const BlogCard2PropsSchema = z.object({
  link: z.string(),
  title: z.string(),

  category: z.string(),
  description: z.string(),
  cardTop: z.custom&lt;ReactNode&gt;()
});

答案4

得分: 0

应该能够使用类似这样的代码:

const scheme = z.object({
  element: z.custom<React.JSX.Element>(
    e => (e as any)?.$$typeof === Symbol.for("react.element"),
    "value must be a React Element"
  ),
})

scheme.safeParse({ element: <div></div> }).success // true
英文:

Should be able to use something like this:

const scheme = z.object({
  element: z.custom&lt;React.JSX.Element&gt;(
    e =&gt; (e as any)?.$$typeof === Symbol.for(&quot;react.element&quot;),
    &quot;value must be a React Element&quot;
  ),
})

scheme.safeParse({ element: &lt;div&gt;&lt;/div&gt; }).success // true

huangapple
  • 本文由 发表于 2023年3月7日 22:22:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/75663212.html
匿名

发表评论

匿名网友

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

确定