我试图在typescript中写一个vscode扩展,我有一个ChildProcess
,我想终止/杀死它。
export declare function terminate(process: ChildProcess & {
pid: number;
}, cwd?: string): boolean;
...
let vlsProcess: ChildProcess
然后我试着打电话
terminate(vlsProcess);
但我有这个错误:
类型“ChildProcess”的参数不能分配给类型“ChildProcess & { pid:number;}'。类型“ChildProcess”不能分配给类型“{ pid:number;}'。属性“pid”在类型“ChildProcess”中是可选的,但在类型“{ pid:number; }'
函数terminate
期望“交集类型
ChildProcess & {
pid: number;
}
但是我目前只有一个ChildProcess
,我如何将ChildProcess
转换为ChildProcess & { pid: number;}
?
我查了ChildProcess,它有
readonly pid?: number | undefined;
所以对我来说,它似乎可以转换为ChildProcess & { pid: number;}
,但typescript编译器说:
属性“pid”在类型“ChildProcess”中是可选的,但在类型“{ pid:number; }'
我该怎么做这个转换?
1条答案
按热度按时间brccelvz1#
terminate(vlsProcess)
编译时没有错误的方法是说服编译器vlsProcess
是ChildProcess & { pid: number; }
类型,这意味着它必须是ChildProcess
,其中pid
属性已知存在,并且类型为number
。但是vlsProcess
被声明为ChildProcess
,其pid
属性是可选的。所以你需要对pid
属性做一些事情。一种方法是在调用
terminate(vlsProcess)
之前写一个typeof vlsProcess.pid === "number"
的检查,希望这样的检查能够narrow是vlsProcess
的明显类型。不幸的是,这不起作用:虽然检查
typeof vlsProcess.pid === "number"
可以将vlsProcess.pid
的表观类型从number | undefined
缩小到number
,但它对vlsProcess
本身的表观类型没有影响。一般来说,检查a.b.c.d.e.f
这样的子属性对所有父对象都有影响是非常昂贵的,因为编译器需要花费时间来合成所有相关类型,其中大部分类型对于大多数调用都是完全无用的。除非有更好的事情发生,否则我们可以通过实现自定义类型保护函数来模拟这种收缩。像这样:
如果
hasDefinedProp(obj, k)
返回true
,则obj
将从其原始类型缩小到已知在k
键处具有已定义属性的子类型。它被写成T
和{ [P in K]: {} | null }
的交集,后者等效于Record<K, {} | null>
,使用Record
实用类型。已知{ [P in K]: {} | null }
类型在K
类型的每个键上都有{} | null
类型的属性,而{} | null
基本上允许除了undefined
之外的所有值。将类型与{} | null
相交将有助于从其域中消除undefined
,如TypeScript 4.8中引入的那样。请注意,该实现使用类型Assert
obj as any
来允许我们毫无怨言地索引到obj[key]
。好吧,现在我们试试:
TypeScript认为缩小的类型
ChildProcess & { pid: {} | null }
可以分配给ChildProcess & { pid: number }
,因为前者的pid
属性是(number | undefined) & ({} | null)
,而后者是number
。如果由于某种原因,
hasDefinedProp()
返回false
,那么您不想调用terminate(vlsProcess)
,因为vlsProcess
没有pid
。在这种情况下,你应该做什么取决于你的用例。在上面的代码中,它只是跳过了terminate()
调用,但是你可能想抛出一个异常或其他东西。Playground链接到代码