为什么以下断言有效:
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 types,SO answer here使您的状态正常运行接口。作为一种解决方法,我提出了setState({a: "a"} as MyState)
并发现只要接口MyState
字段所有非可选,但只要一些}就会失败1} em>属性是可选的。 (使所有属性都是可选的是一种解决方法,但在我的情况下非常不受欢迎。)
答案 0 :(得分:2)
类型断言只能用于在类型和子类型之间进行转换。
假设您声明了以下变量:
declare var foo: number | string;
declare var bar: number;
注意number
是number | 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中试用。