1

在 ReactJS 中,我通常使用这种 destructurnig props 模式(我想这很惯用):

export default function Example({ ExampleProps }) {
  const {
    content,
    title,
    date,
    featuredImage,
    author,
    tags,
  } = ExampleProps || {};

我可以在解构时添加默认值,这增加了一些安全性:

export default function Example({ ExampleProps }) {
  const {
    content = "",
    title = "Missing Title",
    date = "",
    featuredImage = {},
    author = {},
    tags = [],
  } = ExampleProps || {};

但是现在我切换到 TypeScriptstrict模式,我很难过。我的道具是由 GraphQl codegen 输入的,几乎所有的属性都包装在一个Maybe<T>类型中,所以当展开时,有actualValue | null | undefined.

如果值为 ,默认值({ maybeUndefined = ""} = props)可以救我undefined,但null值会通过,所以 TS 编译器在唠叨,我的代码导致很多:

tags?.nodes?.length // etc…

这让我有点紧张,因为可选链的成本一文(尽管我不知道它在 2021 年的相关性如何)。我还听说?.操作员过度使用被称为“代码异味”的一个例子。

是否有一种模式,可能利用??运算符,可以使 TS 编译器高兴并且至少可以清除其中的一些very?.long?.optional?.chains

4

1 回答 1

1

我看到两种可能的选择:

  1. 逐个属性地进行无效合并,或

  2. 使用效用函数

逐个属性

相当缓慢(我是一个缓慢的开发人员):

// Default `ExampleProps` here −−−−−−−−−−−−−−−vvvvv
export default function Example({ ExampleProps = {} }) {
    // Then do the nullish coalescing per-item
    const content = ExampleProps.content ?? "";
    const title = ExampleProps.title ?? "Missing Title";
    const date = ExampleProps.date ?? "";
    const featuredImage = ExampleProps.featuredImage ?? {},
    const author = ExampleProps.author ?? {},
    const tags = ExampleProps.tags ?? [];
    // ...

实用功能

或者,使用沿这些行的实用程序函数将null值(编译时和运行时)转换为undefined,因此您可以在解构结果时使用解构默认值。类型部分相当简单:

type NullToUndefined<Type> = {
    [key in keyof Type]: Exclude<Type[key], null>;
}

那么效用函数可能是这样的:

function nullToUndefined<
    SourceType extends object,
    ResultType = NullToUndefined<SourceType>
>(object: SourceType) {
    return Object.fromEntries(
        Object.entries(object).map(([key, value]) => [key, value ?? undefined])
    ) as ResultType;
}

或像这样(在运行时方面可能更有效):

function nullToUndefined<
    SourceType extends object,
    ResultType = NullToUndefined<SourceType>
>(object: SourceType) {
    const source = object as {[key: string]: any};
    const result: {[key: string]: any} = {};
    for (const key in object) {
        if (Object.hasOwn(object, key)) {
            result[key] = source[key] ?? undefined;
        }
    }
    return result as ResultType;
}

请注意,这Object.hasOwn非常新的,但很容易填充。或者你可以Object.prototype.hasOwn.call(object, key)改用。

(在这两种情况下 nullToUndefined我都在玩类型断言的快速和松散。对于像这样的小型实用程序函数,我认为这是一个合理的折衷方案,前提是输入和输出定义明确。)

然后:

export default function Example({ ExampleProps }) {
    const {
        content = "",
        title = "Missing Title",
        date = "",
        featuredImage = {},
        author = {},
        tags = [],
    } = nullToUndefined(ExampleProps || {});
    //  ^^^^^^^^^^^^^^^^−−−−−−−−−−−−−−−−−−^
    // ...

游乐场链接

于 2021-11-11T13:45:05.583 回答