typescript - 如何定义不包含特定成员的对象类型
问题描述
我正在处理我放入和取出数据库/操作的对象,有时希望添加和删除特定于数据库/操作的字段。
例如,我有:
type EntryEvent<EntryLine> = { type: 'entry' } & EntryLine;
在其他地方,我希望删除该type
成员以便将一个EntryEvent<EntryLine>
back 变成一个EntryLine
. 为此,我使用如下实用程序函数:
export function stripFields<T extends object, K extends keyof T>(
o: T,
fields: K[]
): Omit<T, K> {
const result: Partial<T> = { ...(<object>o) };
for (const field of fields) {
delete result[field];
}
return <Omit<T, K>>result;
}
问题是,生成的对象不会被识别为EntryLine
.
如果我尝试将以下内容分配给EntryLine
类型:
stripFields(event, ['type'])
我会得到:
Argument of type 'Pick<EntryEvent<EntryLine>, Exclude<keyof EntryLine, "type">>' is not assignable to parameter of type 'EntryLine'.
'Pick<EntryEvent<EntryLine>, Exclude<keyof EntryLine, "type">>' is assignable to the constraint of type 'EntryLine', but 'EntryLine' could be instantiated with a different subtype of constraint 'Pick<object, never>' ts(2345)
据我所知,这是有道理的,因为如果泛型类型EntryLine
包含一个type
成员,结果stripFields
将不再是一个EntryLine
(因为它会丢失它的type
成员)。
有什么方法可以定义约束泛型类型EntryLine
,使其不允许具有type
字段的对象?还是有其他解决方法?
更新:
以下代码为我重现了该问题:
type EntryEvent<EntryLine> = { type: "entry" } & EntryLine;
type MyEntryLine = {
a: Date;
};
export function stripFields<T extends object, K extends keyof T>(
o: T,
fields: K[]
): Omit<T, K> {
const result: Partial<T> = { ...(<object>o) };
for (const field of fields) {
delete result[field];
}
return <Omit<T, K>>result;
}
type Callback<EntryLine> = (a: EntryLine) => void;
function thingThatTakesAnEvent<EntryLine>(a: EntryEvent<EntryLine>, callback: Callback<EntryLine>) {
callback(stripFields(a, ["type"]));
}
function thingThatTakesAMyEntryLine(a: MyEntryLine) {
console.log(a.a);
}
declare let event: EntryEvent<MyEntryLine>;
thingThatTakesAnEvent(event, thingThatTakesAMyEntryLine);
解决方案
'Pick< EntryEvent< EntryLine>, Exclude< keyof EntryLine, "type">>' 可分配给类型为“EntryLine”的约束,但可以使用约束“{}”的不同子类型来实例化“EntryLine”。
这种形式的错误消息基本上意味着您试图从传入的泛型类型参数中推断出太多,而只有调用者/客户端才能知道其确切类型。Typescript 不再认为您对其类型的猜测是安全的。
关于你的代码,它可以被翻译成这样:
function thingThatTakesAnEvent<EntryLine>(
a: EntryEvent<EntryLine>,
callback: Callback<EntryLine>
) {
callback(stripFields(a, ["type"]));
//------ error ------//
}
==> 的返回类型stripFields
,即Pick< EntryEvent< EntryLine>, Exclude< keyof EntryLine, "type">>
,可分配给约束EntryLine
(此处默认为{}
),但是如果调用者像这样调用函数怎么办:thingThatTakesAnEvent<{foo: "bar"}>
?在函数内部,我们不知道它是{foo: "bar"}
,我们应该调用callback
with EntryLine
,但是我们使用了一个特定的子类型,这可能不是来自调用者的正确子类型。
根据目的,您可以执行以下操作:
- 更改您的回调类型以匹配
stripFields
Playground的类型:
type Callback<EntryLine> = (a: Omit<EntryEvent<EntryLine>, "type">) => void;
- 在
thingThatTakesAndEvent
Playground中进行演员表:
function thingThatTakesAnEvent<EntryLine>(
a: EntryEvent<EntryLine>,
callback: Callback<EntryLine>
) {
callback((stripFields(a, ["type"]) as unknown) as EntryLine);
}
推荐阅读
- sql-server - 如果它具有允许值之一,是否有办法限制用户进一步更新列
- swift - 重新排序自定义单元格会导致约束混乱
- ios - 如何从顶部定位 NavigationBar x 像素
- javascript - 如何在 Bootstrap 的选项卡中添加链接?
- python - 带有类成员的 pybind11 缓冲区协议
- css - 修复重叠的嵌套 Div 元素
- javascript - 逗号分隔的有效手机号码的正则表达式
- reactjs - 在 fetch 方法中加载状态不会更改为 true
- c# - CPU/IO密集型异步任务(mysql数据库连接失败)
- hiveql - 如何在日期分区中获取最近 3 个月