请考虑以下类型定义:
type ClipBase = { duration: number; }
type AudioClip = ClipBase & {
type: "audio";
volume: number;
}
type VideoClip = ClipBase & {
type: "video";
height: number;
width: number;
}
type MediaClip = ClipBase & {
type: "media";
url: string;
}
type Clip = VideoClip | AudioClip | MediaClip;
我想在Clips数组上使用.filter
并缩小类型。我使用以下助手函数,借用自here:
export function isType<
GenericType extends string,
Union extends { type: GenericType },
SpecificType extends GenericType,
>(val: SpecificType) {
return (obj: Union): obj is Extract<Union, { type: SpecificType }> =>
obj.type === val;
}
如果我只过滤一种类型的剪辑,这将很好地工作:
function getVideoClips(clips: Clip[]) {
return clips.filter(isType("video")); // VideoClip[]
}
但是,如果我想得到区分并集的子集,TypeScript会返回原始类型Clip[]
,即使推断过滤器应该输出什么类型应该很简单。
function getAudioAndMediaClips(clips: Clip[]) {
return clips.filter(clip => isType("audio")(clip) || isType("media")(clip)); // Clip[]
}
在Typescript Playground上的完整示例。
我能做些什么来帮助TypeScript成功地从一个区分的联合中推断出多个类型,而不必为每对类型编写特定的帮助函数?
2条答案
按热度按时间92dk7w1h1#
类型 predicate 不是从函数实现中推断出来的,所以
clip => isType("audio")(clip) || isType("media")(clip)
不是类型保护函数。microsoft/TypeScript#38390中有一个建议,允许编译器自动将某些简单的函数实现视为类型保护函数,但现在它不是语言的一部分。除非实现了这样的功能,否则如果希望函数成为类型保护函数,则需要使用类型 predicate 注解其返回类型。例如:
在这里,你明确地告诉编译器回调返回
clip is AudioClip | MediaClip
,因此整个函数的返回类型是(AudioClip | MediaClip)[]
。如果你不想手动完成,你需要写一个更通用的类型保护函数,它可以作用于单个
type
和多个type
。例如,你可以将isType
重写为variadic,并接受多个判别式值而不是一个:您可以像以前一样使用此命令:
但是你也可以传递一个额外的参数:
看起来不错!
Playground链接
ufj5ltwl2#
您可以创建一个函数来合并
is
函数