"Cannot invoke an object which is possibly 'undefined'" 即使在确保它之后 !== undefined
"Cannot invoke an object which is possibly 'undefined'" even after ensuring it !== undefined
为什么我在检查 func
引用未定义后仍会出现 Cannot invoke an object which is possibly 'undefined'
Typescript 错误?
type Hoge = {
func?: (str: string) => boolean
}
const myFunc = (obj: Hoge) => {
const data = ['AAA', 'BBB', 'CCC']
if(obj.func !== undefined) {
data.filter(obj.func) // ok
data.filter(v => obj.func(v)) // ng Cannot invoke an object which is possibly 'undefined'.
}
}
它在最后一行,您需要有条件地处理 obj.func 未定义的情况,以便将 v
传递给它:
func
的手写体
func?: ((str: string) => boolean) | undefined
使用三元有条件地处理 undefined 满足这个:
type Hoge = {
func?: (str: string) => boolean
}
const myFunc = (obj: Hoge) => {
const data = ['AAA', 'BBB', 'CCC']
if(obj.func !== undefined) {
data.filter(obj.func) // ok
data.filter(v => obj.func ? obj.func(v) : console.log('obj.func undefined')) // ng Cannot invoke an object which is possibly 'undefined'.
}
}
好吧 你 知道 data.filter
的回调会立即执行,但 typescript 应该如何知道?
考虑这个例子:
type Hoge = {
func?: (str: string) => boolean
}
const myFunc = (obj: Hoge) => {
if(obj.func !== undefined) {
setTimeout(() => obj.func!('a'), 100); // Force assume func is not undefined
}
obj.func = undefined; // TS will allow this since func can be undefined, but this is a problem
}
myFunc({
func: (str: string) => {
console.log(str); return true;
}
})
因为在您的情况下您确实知道函数是在 if 块中调用的,所以您应该使用:
data.filter(v => obj.func!(v))
这会让 TS 知道你知道函数在那个时候不是未定义的
简答
Control flow analysis很复杂,Typescript的分析也就到此为止了。在这种情况下,很容易证明在 //ok
行上,data.func !== undefined
。但是要证明 data.func
的值在它被调用之前不会改变并不容易 将来某个时候 在传递给 data.filter
的闭包中。
请参阅此答案末尾的解决方案。
长答案
Type narrowing is achieved by using control flow analysis 以证明特定行上的引用具有比其最初声明或先前已知类型更窄的类型。
换行
data.filter(obj.func) // ok
控制流分析很简单; obj.func
在检查为 !== undefined
后立即取消引用。
但在下一行
data.filter(v => obj.func(v))
obj.func
不会立即取消引用。它只出现在下一行 lexically。但实际上,它直到稍后才会被调用,在 data.filter
的执行“内部”。 Typescript 必须递归地进行控制流分析,直至 data.filter
的实现。显然,在这种情况下并非如此。也许未来版本的 Typescript 会(they keep improving it)。或者它可能太复杂或太昂贵。或者这不可能?
Help me improve this answer
Does Javascript's "single threaded architecture" mean that no other thread can change the value of obj.func
before data.filter
is finished?
自己看看
将以下代码放入您的 IDE 或尝试 in the Typescript Playground。观察 a
、b
、c
、d
和 e
的类型。请注意 c
, 词法 出现在 b
和 d
之间,如何具有不同的类型。这是因为 wrappingFunc
实际上并没有在 b
和 d
之间执行。 c
的类型不能仅仅因为它按词法出现在 if 子句中而被缩小。注意在调用 wrappingFunc
之前如何修改 obj.func
的值:
type Hoge = {
func?: (str: string) => boolean
}
const myFunc = (obj: Hoge) => {
const data = ['AAA', 'BBB', 'CCC']
const a = obj.func // ((str: string) => boolean) | undefined
if(obj.func !== undefined) {
const b = obj.func // (str: string) => boolean
const wrappingFunc = function () {
const c = obj.func // ((str: string) => boolean) | undefined
c() // ERROR
}
const d = obj.func // (str: string) => boolean
obj.func = undefined // modify obj.func before calling wrappingFunc
wrappingFunc() // this call will fail; Typescript catches this possibility above
}
const e = obj.func // ((str: string) => boolean) | undefined
}
解决方案
修复错误的一种方法是使用类型断言,这基本上是对 Typescript 说:“你可能不知道类型,但我知道,所以相信我。”:
const myFunc = (obj: Hoge) => {
const data = ['AAA', 'BBB', 'CCC']
if(obj.func !== undefined) {
data.filter(obj.func) // ok
data.filter(v => (obj.func as (str: string) => boolean)(v) )
}
}
另一种方法是将 obj.func
的值赋给闭包中的一个变量,Typescript 可以很容易地证明它从未被修改过:
const myFunc = (obj: Hoge) => {
const data = ['AAA', 'BBB', 'CCC']
if(obj.func !== undefined) {
data.filter(obj.func) // ok
const filterFunc = obj.func
data.filter(v => filterFunc(v)) // ok
}
}
为什么我在检查 func
引用未定义后仍会出现 Cannot invoke an object which is possibly 'undefined'
Typescript 错误?
type Hoge = {
func?: (str: string) => boolean
}
const myFunc = (obj: Hoge) => {
const data = ['AAA', 'BBB', 'CCC']
if(obj.func !== undefined) {
data.filter(obj.func) // ok
data.filter(v => obj.func(v)) // ng Cannot invoke an object which is possibly 'undefined'.
}
}
它在最后一行,您需要有条件地处理 obj.func 未定义的情况,以便将 v
传递给它:
func
func?: ((str: string) => boolean) | undefined
使用三元有条件地处理 undefined 满足这个:
type Hoge = {
func?: (str: string) => boolean
}
const myFunc = (obj: Hoge) => {
const data = ['AAA', 'BBB', 'CCC']
if(obj.func !== undefined) {
data.filter(obj.func) // ok
data.filter(v => obj.func ? obj.func(v) : console.log('obj.func undefined')) // ng Cannot invoke an object which is possibly 'undefined'.
}
}
好吧 你 知道 data.filter
的回调会立即执行,但 typescript 应该如何知道?
考虑这个例子:
type Hoge = {
func?: (str: string) => boolean
}
const myFunc = (obj: Hoge) => {
if(obj.func !== undefined) {
setTimeout(() => obj.func!('a'), 100); // Force assume func is not undefined
}
obj.func = undefined; // TS will allow this since func can be undefined, but this is a problem
}
myFunc({
func: (str: string) => {
console.log(str); return true;
}
})
因为在您的情况下您确实知道函数是在 if 块中调用的,所以您应该使用:
data.filter(v => obj.func!(v))
这会让 TS 知道你知道函数在那个时候不是未定义的
简答
Control flow analysis很复杂,Typescript的分析也就到此为止了。在这种情况下,很容易证明在 //ok
行上,data.func !== undefined
。但是要证明 data.func
的值在它被调用之前不会改变并不容易 将来某个时候 在传递给 data.filter
的闭包中。
请参阅此答案末尾的解决方案。
长答案
Type narrowing is achieved by using control flow analysis 以证明特定行上的引用具有比其最初声明或先前已知类型更窄的类型。
换行
data.filter(obj.func) // ok
控制流分析很简单; obj.func
在检查为 !== undefined
后立即取消引用。
但在下一行
data.filter(v => obj.func(v))
obj.func
不会立即取消引用。它只出现在下一行 lexically。但实际上,它直到稍后才会被调用,在 data.filter
的执行“内部”。 Typescript 必须递归地进行控制流分析,直至 data.filter
的实现。显然,在这种情况下并非如此。也许未来版本的 Typescript 会(they keep improving it)。或者它可能太复杂或太昂贵。或者这不可能?
Help me improve this answer
Does Javascript's "single threaded architecture" mean that no other thread can change the value of
obj.func
beforedata.filter
is finished?
自己看看
将以下代码放入您的 IDE 或尝试 in the Typescript Playground。观察 a
、b
、c
、d
和 e
的类型。请注意 c
, 词法 出现在 b
和 d
之间,如何具有不同的类型。这是因为 wrappingFunc
实际上并没有在 b
和 d
之间执行。 c
的类型不能仅仅因为它按词法出现在 if 子句中而被缩小。注意在调用 wrappingFunc
之前如何修改 obj.func
的值:
type Hoge = {
func?: (str: string) => boolean
}
const myFunc = (obj: Hoge) => {
const data = ['AAA', 'BBB', 'CCC']
const a = obj.func // ((str: string) => boolean) | undefined
if(obj.func !== undefined) {
const b = obj.func // (str: string) => boolean
const wrappingFunc = function () {
const c = obj.func // ((str: string) => boolean) | undefined
c() // ERROR
}
const d = obj.func // (str: string) => boolean
obj.func = undefined // modify obj.func before calling wrappingFunc
wrappingFunc() // this call will fail; Typescript catches this possibility above
}
const e = obj.func // ((str: string) => boolean) | undefined
}
解决方案
修复错误的一种方法是使用类型断言,这基本上是对 Typescript 说:“你可能不知道类型,但我知道,所以相信我。”:
const myFunc = (obj: Hoge) => {
const data = ['AAA', 'BBB', 'CCC']
if(obj.func !== undefined) {
data.filter(obj.func) // ok
data.filter(v => (obj.func as (str: string) => boolean)(v) )
}
}
另一种方法是将 obj.func
的值赋给闭包中的一个变量,Typescript 可以很容易地证明它从未被修改过:
const myFunc = (obj: Hoge) => {
const data = ['AAA', 'BBB', 'CCC']
if(obj.func !== undefined) {
data.filter(obj.func) // ok
const filterFunc = obj.func
data.filter(v => filterFunc(v)) // ok
}
}