gpt4 book ai didi

typescript 与联合的交集导致不存在的属性

转载 作者:行者123 更新时间:2023-12-03 07:38:04 24 4
gpt4 key购买 nike

在下面的示例中,我定义了 Typescript 类型以从索引中请求数据。
有两种从索引服务器检索数据 block 的高效方法,要么 通过 startKey,endKey 通过 startKey,limit (键的计数)。
在组合这些替代案例以在 Typescript 中定义请求时,我做错了,我看不到是什么,除非我与联合相交的方法没有意义或者我不理解 typescript 错误。

interface StartKey {
startKey: string;
}

interface EndKey {
endKey: string;
}

interface Limit {
limit: number;
}

type KeyRange = StartKey & EndKey;

type KeyLimit = StartKey & Limit;

type KeyBounds = KeyRange | KeyLimit;

export type Options = {
someparam:string
} & KeyBounds;

function retrieve(options:Options){
const {
startKey,
endKey, //this line causes a compiler error
limit, //this line causes a compiler error
} = options;
}
首先我创建了两个备用接口(interface) 键程 (有 endKey)和 键限 (有限制)。然后我将这些接口(interface)合并为 键界 类型。那 键界 然后在编写请求时通过与其他特定于索引请求的参数的交集来组合类型。例如使用 请求项目选项 应该能够使用一种或另一种策略来限制返回的结果。
This playground显示了我目前正在采用的方法以及我从选项的定义中得到的(对我而言)令人惊讶的错误......
  • “选项”类型上不存在属性“endKey”。
  • “选项”类型上不存在属性“限制”。

  • 我希望会有 一些获取 endKey OR 限制的路径,因为 Options 包括具有这些属性的类型的联合。任何时候最多有一个出现,但这就像拥有一个不会引发编译器错误的可选属性。
    导致错误的解构正是当我试图明确验证已请求哪个备用键边界签名时(我期望一个或其他属性未设置)。
    相比之下,这些显式可选的代码将解构 NOT 视为错误情况,即使 endKey 和 limit 对于任何特定对象都可能未定义。我期望与联合的交集会产生类似的数据结构,除非编译器知道可能存在 endKey 异或 一个限制。
    interface KeyRange {
    startKey:string
    endKey?:string
    limit?:string
    }

    function retrieve(range:KeyRange){
    const {
    startKey,
    endKey,
    limit,
    } = range;
    }
    得到一个在结果类型上根本不存在的错误(甚至不是可选的)让我感到惊讶,这表明我错过了一些东西。谁能告诉我我需要做什么才能使这些替代品有效?

    最佳答案

    一般来说,您不能访问联合类型值的属性,除非该属性键已知存在于联合的每个成员中:

    interface Foo {
    foo: string;
    }
    interface Bar {
    bar: string;
    }
    function processFooOrBar(fooOrBar: Foo | Bar) {
    fooOrBar.foo; // error!
    // Property 'foo' does not exist on type 'Foo | Bar'.
    // Property 'foo' does not exist on type 'Bar'
    }
    错误消息有点误导。当编译器提示“属性 foo 不存在于类型 Foo | Bar 上”时,它实际上意味着“属性 foo 不知道存在于类型 Foo | Bar 的值中”。该属性当然有可能存在,但因为 Bar 类型的值不一定有这样的属性,编译器会警告你。

    如果你有一个联合类型的值并且想要访问只存在于联合的一些成员上的属性,你需要做一些 narrowing通过类型保护的值。例如,您可以使用 in运算符作为类型保护(由 microsoft/TypeScript#15256 实现):
      if ("foo" in fooOrBar) {
    fooOrBar.foo.toUpperCase(); // okay
    } else {
    fooOrBar.bar.toUpperCase(); // okay
    }
    在您的情况下,这意味着将您的解构分为两种情况:
      let startKey: string;
    let endKey: string | undefined;
    let limit: number | undefined;
    if ("endKey" in options) {
    const { startKey, endKey } = options;
    } else {
    const { startKey, limit } = options;
    }
    (这个 in 类型保护很有用,但在技术上是不安全的,因为对象类型在 TypeScript 中是开放和可扩展的。可以得到一个带有 Bar 属性的 foo 对象,如下所示:
    const hmm = { bar: "hello", foo: 123 };
    processFooOrBar(hmm); // no error at compiler time, but impl will error at runtime
    所以要小心......但在实践中这种情况很少发生)

    您可以处理此问题的另一种方法是在进行解构之前扩展为具有显式可选属性的类型。您已经将其作为一种解决方法,但您无需触摸 Options键入自己。只需加宽 options来自 Options 的值类似于 StartKey & Partial<EndKey & Limit> :
    const widerOptions: StartKey & Partial<EndKey & Limit> = options;    
    const {
    startKey,
    endKey,
    limit,
    } = widerOptions;

    最后可以改写 Options明确地成为一个“XOR”版本,编译器知道如果您检查联合的“错误”一侧的属性,则值将是 undefined :
    type XorOptions = {
    startKey: string,
    endKey?: never,
    limit: number,
    someParam: string
    } | {
    startKey: string,
    endKey: string,
    limit?: never,
    someParam: string
    }
    这与您的 Options 不同。在 XorOptions 的每个成员中union 明确提到了每个属性。然后你可以毫无问题地解构:
    function retrieve2(options: XorOptions) {
    const {
    startKey,
    endKey,
    limit,
    } = options;
    }
    Playground link to code

    关于 typescript 与联合的交集导致不存在的属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65490409/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com