当前位置: 首页 > 面试题库 >

为什么对象文字“ {a}”的TypeScript断言只能与接口“ {a,b}”一起使用,而不能与“ {a?,b}”接口一起使用?

桂坚
2023-03-14
问题内容

为什么以下断言起作用:

interface AllRequired {
    a: string;
    b: string;
}

let all = {a: "foo"} as AllRequired; // No error

但是这个断言给出了一个错误:

interface SomeOptional {
    a?: string;
    b: string;
}

let some = {a: "foo"} as SomeOptional; // Error: Property 'b' missing

我能看到的唯一区别是使接口属性之一为可选(?)。似乎如果所有属性都不是可选的,那么我可以向接口声明一个部分对象,但是一旦任何接口属性都是可选的,我就不能再声明一个部分对象。这对我来说真的没有意义,我一直无法找到这种行为的解释。这里发生了什么?

对于上下文:我在尝试解决React的部分状态对象问题时遇到了此行为setState(),但是TypeScript尚没有部分类型来使其在您的状态接口下正常工作。作为一种变通方法,我想出了setState({a:"a"} asMyState),发现这个工作,只要接口MyState字段是 所有 非可选,但一旦失败, 一些
属性是可选的。(将所有属性设置为可选是一种解决方法,但是在我看来,这是非常不希望的。)


问题答案:

类型断言只能用于在类型和子类型之间进行转换。

假设您声明了以下变量:

declare var foo: number | string;
declare var bar: number;

注意number是一个 亚型number|string,这意味着匹配的类型的任何值number(例如3)也匹配number | string。因此,允许使用类型断言在这些类型之间进行转换:

bar = foo as number; /* convert to subtype */
foo = bar as number | string; /* convert to supertype (assertion not necessary but allowed) */

同样,{ a: string, b: string }是的子类型{ a: string }。任何匹配{ a: string, b: string }(例如{ a: "A", b: "B" })的值也将匹配{ a: string },因为它具有atype属性string

相反,两者都不是{ a?: string, b: string }{ a: string }不是另一个的亚型。一些值(例如{ b: "B" })仅匹配前者,而其他值(例如)仅{ a: "A" }匹配后者。

如果您 确实 需要在不相关的类型之间进行转换,则可以通过使用常见的超类型(例如any)作为中间方法来解决此问题:

let foo = ({ a: "A" } as any) as { a?: string, b: string };

规范中的相关部分是4.16类型断言:

e形式的类型声明表达式中,e由T在上下文中键入(第4.23节),并且要求将 e 的结果类型分配给T,或者将T分配给t的扩展形式。
e的结果类型,否则会发生编译时错误。



 类似资料:
  • 问题内容: 我尝试了一些代码,使用XOR在Java中交换两个整数而不使用第三个变量。 这是我尝试的两个交换函数: 这段代码产生的输出是这样的: 我很好奇,为什么这样说: 与这个不同吗? 问题答案: 问题是评估的顺序: 参见JLS第15.26.2节 首先,对左操作数求值以产生一个变量。 如果该评估突然完成,则赋值表达式由于相同的原因而突然完成;右边的操作数不会被评估,并且不会发生赋值。 否则,将保存

  • 我尝试了一些代码在Java中交换两个整数,而不使用第三个变量,即使用XOR。 以下是我尝试的两个交换函数: 该代码产生的输出如下: 我很想知道,为什么会有这样的说法: 和这个不一样?

  • 问题内容: 今天,我发现了python语言一个有趣的“功能”,这让我感到非常悲伤。 那个怎么样?我以为两者是等同的!更糟糕的是,这是我调试时遇到的麻烦的代码 WTF!我的代码中包含列表和字典,并且想知道我到底怎么把dict的键附加到列表上而又没有调用.keys()。事实证明,这就是方法。 我认为这两个陈述是等效的。即使忽略这一点,我也可以理解将字符串追加到列表的方式(因为字符串只是字符数组),但是

  • 问题内容: 这是我必须弄清楚怎么可能的代码。我有一个线索,但我不知道该怎么做。我认为这与负数和正数有关,也可能与变量修饰符有关。我是一个初学者,我到处都看过解决方案,但是找不到可用的东西。 问题是:您需要声明和初始化两个变量。如果条件必须为真。 代码: 感谢您抽出宝贵的时间。 问题答案: 这对于基本类型是不可能的。您可以使用带框的整数来实现: 在和比较将使用未装箱的值1,而将比较引用,并会成功,因

  • 假设我有下面的代码... 不管类ImplementTwo是同时实现B和A,还是只实现B,它仍然需要在接口A中实现方法A(),因为接口B扩展了接口A。有什么理由显式地这样做吗 而不只是 ?

  • 我正在阅读SICP的树递归,其中是通过线性递归计算的。 我们还可以制定一个迭代过程来计算斐波那契数。其思想是使用一对整数a和b,初始化为Fib(1)=1和Fib(0)=0,并重复应用同时变换 不难证明,在应用该变换n次后,a和b将分别等于Fib(n1)和Fib(n)。因此,我们可以使用该过程迭代计算斐波那契数 (由Emacs Lisp重写,代替Scheme) “设置a b=a和b=a,我很难把我的