如何在 TypeScript 中检查产品类型是否详尽?

问题描述 投票:0回答:1

在 TypeScript 中检查和类型的详尽性非常容易。

type Sum =
    | { tag: 'num'; value: number }
    | { tag: 'str'; value: string };

const len = (sum: Sum): number => {
    switch (sum.tag) {
        case 'num': return sum.value;
        case 'str': return sum.value.length;
        default: throw new Error(`Unhandled sum ${sum satisfies never}`);
    }
};

现在,如果我向

Sum
类型添加新变体,则
sum
将不再可分配给
unhandled
。因此,我们会因为不详尽而收到编译时错误。

如何对 TypeScript 中的产品类型执行相同的操作?考虑以下示例。

type Product = {
    num: number;
    str: string;
};

const repeat = (product: Product): string => {
    const { num, str } = product;
    return str.repeat(num);
};

现在,如果我向

Product
类型添加一个新属性,那么我希望 TypeScript 编译器报告不详尽的错误,因为新属性尚未被解构和使用。我该怎么做?

如果代码因不详尽而引发运行时错误,则加分。

typescript pattern-matching destructuring type-safety algebraic-data-types
1个回答
0
投票

为了不详尽,我们首先抛出一个运行时错误。我们可以通过解构其余属性来实现这一点,并在它具有一个或多个可枚举键时抛出错误。

const repeat = (product: Product): string => {
    const { num, str, ...props } = product;
    if (Object.keys(props).length > 0) {
        throw new Error(`Unhandled props ${props}`);
    }
    return str.repeat(num);
};

接下来,为了让 TypeScript 在编译时检查是否详尽,我们可以执行以下操作。

const repeat = (product: Product): string => {
    const { num, str, ...props } = product;
    const unhandled: {} extends typeof props ? {} : never = props;
    if (Object.keys(unhandled).length > 0) {
        throw new Error(`Unhandled props ${unhandled}`);
    }
    return str.repeat(num);
};

这是它的工作原理。

  1. 空对象类型
    {}
    只能分配给
    typeof props
    当且仅当
    props
    是一个空对象。
  2. 因此,当
    props
    为空对象时,
    unhandled
    的类型为
    {}
    ,一切正常。
  3. 但是,当
    props
    不是空对象时,
    unhandled
    的类型为
    never
    ,我们会收到编译时错误。

因此,上述代码将在解构时检查产品类型的详尽性。如果将新属性添加到

Product
类型,则
props
将不再可分配给
unhandled
,并且我们将收到非详尽的编译时错误。

此外,您可以打开

@typescript-eslint/no-unused-vars
规则以确保使用所有解构属性。确保将
ignoreRestSiblings
选项设置为
false

© www.soinside.com 2019 - 2024. All rights reserved.