Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Typescript 类型脚本与联合的交集导致不存在属性_Typescript_Compiler Errors_Properties_Intersection_Discriminated Union - Fatal编程技术网

Typescript 类型脚本与联合的交集导致不存在属性

Typescript 类型脚本与联合的交集导致不存在属性,typescript,compiler-errors,properties,intersection,discriminated-union,Typescript,Compiler Errors,Properties,Intersection,Discriminated Union,在下面的示例中,我定义了Typescript类型以从索引请求数据 有两种从索引服务器检索数据块的有效方法,通过startKey、endKey或通过startKey、limit(键数)检索 在组合这些备选案例来定义Typescript中的请求时,我做了一些错误的事情,我看不出是什么,除非我的相交联合的方法没有意义,或者我不理解Typescript错误 interface StartKey { startKey: string; } interface EndKey { endKey: s

在下面的示例中,我定义了Typescript类型以从索引请求数据

有两种从索引服务器检索数据块的有效方法,通过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;
} 
首先,我创建了两个可选接口KeyRange(有endKey)和KeyLimit(有limit)。然后我将这些接口合并成一个KeyBounds类型。然后,在编写请求时,KeyBounds类型通过与其他索引请求特定参数的交集进行组合。例如,使用选项请求项目应能够使用一种或另一种策略来限制返回的结果

显示了我目前正在采取的方法,以及我从选项定义中得到的令人惊讶的错误

  • 类型“Options”上不存在属性“endKey”
  • 类型“Options”上不存在属性“limit”
我希望会有一些路径来获取endKey或limit,因为选项包括具有这些属性的类型的并集。它们中最多有一个在任何时候都会出现,但这就像拥有一个可选属性一样,它不会引发编译器错误

导致错误的解构正是在我尝试显式验证已请求的备用密钥边界签名时发生的(我希望有一个或其他属性未设置)

相比之下,这段代码在显式可选的情况下不会将分解视为错误情况,即使对于任何特定对象,endKey和limit可能都未定义。我期望与并集的交集会产生类似的数据结构,除非编译器知道可能存在endKeyXOR限制

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
类型的值不一定具有这样的属性,编译器会警告您


若您有一个联合类型的值,并且希望访问仅存在于联合的某些成员上的属性,那个么需要通过类型保护执行某种类型的值。例如,您可以使用中的
运算符作为类型保护(由以下实现):

在您的情况下,这意味着将您的分解分为两种情况:

  let startKey: string;
  let endKey: string | undefined;
  let limit: number | undefined;
  if ("endKey" in options) {
    const { startKey, endKey } = options;
  } else {
    const { startKey, limit } = options;
  }
(类型保护中的
很有用,但在技术上不安全,因为对象类型在TypeScript中是开放的和可扩展的。可以使用
foo
属性获取
Bar
对象,如下所示:

const hmm = { bar: "hello", foo: 123 };
processFooOrBar(hmm); // no error at compiler time, but impl will error at runtime
所以要小心……但实际上这种情况很少发生)


处理此问题的另一种方法是,在进行分解之前,扩展到具有显式可选属性的类型。您已经将此作为一种解决方法,但不需要触摸
选项
类型本身。只需将
options
值从
options
扩大到类似
StartKey&Partial

这不同于您的
选项
,因为
XorOptions
联合的每个成员都明确提到了每个属性。然后,您可以无问题地分解结构:

function retrieve2(options: XorOptions) {
  const {
    startKey,
    endKey,
    limit,
  } = options;
}

在@jcalz建议的基础上,我定义了KeyBounds,通过引入一个Xor类型,可以交替使用endKey或limit来实现,但不能同时使用两者。这将强制未使用路径(A或B)中的属性名称具有类型从不,而不是没有定义

一旦有了一个定义,即使它有时解析为“永不”,那么分解结构也可以毫无错误地发生

type Xor<A, B> =
  | (A & { [k in keyof B]?: never })
  | (B & { [k in keyof A]?: never });

interface StartKey {
  startKey: string;
}

interface EndKey {
  endKey: string;
}

interface Limit {
  limit: number;
}

type KeyBounds = StartKey & Xor<EndKey, Limit>;

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

function retrieve(options:Options){
    const {
        startKey,
        endKey,
        limit,
    } = options;
} 
类型Xor=
|(A&{[k in keyof B]?:never})
|(B&{[k in keyof A]?:never});
接口启动键{
startKey:字符串;
}
接口结束键{
endKey:字符串;
}
界面极限{
限制:数量;
}
类型KeyBounds=StartKey&Xor;
导出类型选项={
someparam:string
}&KeyBounds;
函数检索(选项:选项){
常数{
startKey,
结束键,
极限,
}=期权;
} 

KeyRange | KeyLimit
仅与一个属性
startKey
type:D[“type”]重叠
只提供了额外的属性
type
@Silvermind我所期望的是limit和endKey只是有时存在,而不是它们根本不存在,因此引发编译器错误。我希望联合的交集的行为类似于下面的游乐场,其中endKey和limit都是可选的,但它们的解构(即使未定义)这不是一个错误吗@Silvermind我添加了一个对比的例子来澄清这个问题。然后,也许你需要通过使用部分联合来选择它:
type KeyBounds=partial&partial
@Silvermind解决了错误,但引入了一种不幸的情况,即API现在表明endKey和limit一起可能有意义,即使它们没有意义。以前的战略
type XorOptions = {
  startKey: string,
  endKey?: never,
  limit: number,
  someParam: string
} | {
  startKey: string,
  endKey: string,
  limit?: never,
  someParam: string
}
function retrieve2(options: XorOptions) {
  const {
    startKey,
    endKey,
    limit,
  } = options;
}
type Xor<A, B> =
  | (A & { [k in keyof B]?: never })
  | (B & { [k in keyof A]?: never });

interface StartKey {
  startKey: string;
}

interface EndKey {
  endKey: string;
}

interface Limit {
  limit: number;
}

type KeyBounds = StartKey & Xor<EndKey, Limit>;

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

function retrieve(options:Options){
    const {
        startKey,
        endKey,
        limit,
    } = options;
}