为什么对象文字`{a}`的TypeScript断言与接口`{a,b}`有效但不是`{a?,b}`

时间:2016-04-15 16:43:32

标签: reactjs typescript

为什么以下断言有效:

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

我能看到的唯一区别是使其中一个接口属性可选(?)。似乎所有属性都不是可选的,我可以断言接口的部分对象,但只要任何接口属性是可选的,我就不能断言部分对象了。这对我来说并没有多大意义,我也无法找到对此行为的解释。这里发生了什么?

对于上下文:我encountered this behavior在尝试解决React的setState()采用部分状态对象的问题时,我TypeScript doesn't yet have partial typesSO answer here使您的状态正常运行接口。作为一种解决方法,我提出了setState({a: "a"} as MyState)并发现只要接口MyState字段所有非可选,但只要一些属性是可选的。 (使所有属性都是可选的是一种解决方法,但在我的情况下非常不受欢迎。)

2 个答案:

答案 0 :(得分:2)

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

假设您声明了以下变量:

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

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

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 }类型的a属性。

相比之下,string{ a?: string, b: string }都不是另一个的子类型。 某些值(例如{ a: string })仅匹配前者,而其他值(例如{ b: "B" })仅匹配后者。

如果确实需要在不相关的类型之间进行转换,可以使用常用的超类型(例如{ a: "A" })作为中间件来解决此问题:

any

规范中的相关部分是4.16 Type Assertions

  

在<形式的类型断言表达式中。 T> e,e由上下文键入(第4.23节),结果类型 e 需要可分配给T,或者T需要可分配给结果类型的e的加宽形式,或者发生编译时错误。

答案 1 :(得分:0)

嗯,这只是一个理论,但我有一些代码支持它。

在您的第一个示例中,当您转向C:\wamp\bin\mysql\mysql5.6.17\bin\mysqld.exe --console 时,您基本上会向编译器说出您知道自己在做什么,并且您将设置{{1}的值以后。

在第二个例子中,你认为你正在做同样的事情,但编译器可能认为"嘿,如果他设置了可选属性,他必须设置一个完整的对象"因此,对于为什么AllRequired的值在此完整对象中缺失而感到困惑。

这听起来有点牵强,但在这里:

all.b

如果您使用条件,则错误消失,因为那时(好吧,可能)some.b实际上是可选的。

playground中试用。