javascript - 为联合类型和泛型编写巧妙的类型保护
问题描述
我有以下结构:
const fragmentTypes = [
'Word',
'Sentence',
] as const;
type FragmentType = typeof fragmentTypes[number];
interface IFragmentData {
type: FragmentType;
}
interface IFragment<T extends IFragmentData> {
id: string;
type: T['type'];
data: Omit<T, 'type'>;
}
interface IWordFragmentData extends IFragmentData {
type: 'Word';
word: string;
}
interface ISentenceFragmentData extends IFragmentData {
type: 'Sentence';
sentence: string;
}
type Fragment =
| IFragment<IWordFragmentData>
| IFragment<ISentenceFragmentData>;
并知道有挑战,我经常filter
碎片。我目前的方式是通过以下类型保护:
function isFragmentType<T extends IFragmentData>(t: FragmentType) {
return (x: Fragment | IFragment<T>): x is IFragment<T> => {
return x.type === t;
};
}
console.log(isFragmentType<IWordFragmentData>('Word')({type: 'Word', id: 'test123', data: {word: 'test123'}}));
这工作正常,但留下了将 aIFragmentData
与 wrong结合的选项FragmentType
。例如 : isFragmentType<IMarkFragmentData>('Sentence')
将是有效代码,即使 'Sentence' 是该IMarkFragmentData
类型的错误鉴别器。
有没有更聪明的方法来编写我的类型保护甚至重组我的打字?
解决方案
isFragmentType()
您的函数的主要问题是类型t
根本不受T
. 我可能会重写它以T
表示该type
属性,并使用实用Extract
程序类型来过滤Fragment
具有该属性的成员的联合type
:
function isFragmentType<T extends Fragment['type']>(t: T) {
return (x: Fragment): x is Extract<Fragment, { type: T }> => {
return x.type === t;
};
}
您可以验证它是否按需要工作(并且您不必手动指定T
,因为它可以从 的类型推断t
):
function processFragment(f: Fragment) {
if (isFragmentType("Word")(f)) {
f.data.word.toUpperCase(); // okay
} else {
f.data.sentence.toUpperCase(); // okay
}
}
仅供参考,我不确定为什么isFragmentType()
是curried,但它看起来不需要:
function isFragmentType<T extends Fragment['type']>(
t: T, x: Fragment
): x is Extract<Fragment, { type: T }> {
return x.type === t;
}
function processFragment(f: Fragment) {
if (isFragmentType("Word", f)) {
f.data.word.toUpperCase(); // okay
} else {
f.data.sentence.toUpperCase(); // okay
}
}
推荐阅读
- r - R:使用 sqldf 根据 ID 和时间连接两个数据帧
- android - 图书馆项目中的Android动态交付
- html - HTML 表格格式 - 基于内容的动态列宽
- python - Python 混合和类型、依赖项
- python-3.x - 单箭头箭袋图似乎不适用于 cartopy PlateCarree 变换
- javascript - 将(例如)Ymd 字符串从 PHP 转换为 JS 中的等效日期格式
- spring - 当具有不同端口的 2 个应用程序通过 2 个不同的端口监听同一个 kafka 主题时,如何避免重复消息?
- python - 如何在不中断循环的情况下返回变量?
- asp.net-mvc - 如何在 Visual Studio 中使用 Visual Studio Code 方式编写 HTML 标签?
- r - 在 R 中添加一行计算