我想将类型A转换为类型B,但如果我选择的属性未在两种类型上定义,我想得到警告。
type Source = {
id: number;
foo: string;
onlyOnSource: string;
}
type Target = {
id: number;
foo: string;
onlyOnTarget?: string;
}
const source: Source = {
id: 1,
foo: 'hello',
onlyOnSource: 'test',
}
const transformer1 = (response?: Source): Partial<Target> => {
return {
id: response?.id,
foo: response?.foo,
// wrong: undefined, // cool. error is catched: Object literal may only specify known properties, and 'wrong' does not exist in type 'Partial<Target>'
// onlyOnTarget: response?.onlyOnTarget, // cool. error is catched: Property 'onlyOnTarget' does not exist on type 'Source'
};
};
...总的来说,这是最好的。但是我必须写所有的属性两次(id,foo)。而且可能会给它们赋值错误(例如id: response?.foo
)
所以我尝试了一个通用的“safePick”函数(它类似于lodash/pick,但是当属性不存在时会发出警告)
const safePick = <T, K extends keyof T>(source?: T, ...keys: K[]): Partial<Pick<T, K>> => {
if (!source) return {};
const target: Partial<Pick<T, K>> = {};
keys.forEach(key => {
if (source[key] !== undefined) target[key] = source[key];
});
return target;
};
const transformer2 = (response?: Source): Partial<Target> => {
// return safePick(response, 'id', 'foo', 'wrong'); // cool. error is catched: Argument of type '"wrong"' is not assignable to parameter of type 'keyof Source'
return safePick(response, 'id', 'foo', 'onlyOnSource'); // WRONG! 'onlyOnSource' should not be alowed on type Target!
};
但是,当我将属性“onlyOnSource”赋给类型Target时,这并不是抱怨。
即使我去掉了“部分”部分,它还是不在乎。
但是我希望这个操作失败并给出一个警告,理想的情况是以一种通用的方式,这样我就不必手动传递两种类型的所有键。
我试了很多方法,甚至用了“zod”,但都找不到一个好的解决方法,有人有什么好主意吗?
1条答案
按热度按时间jogvjijk1#
你必须把
Target
类型也作为函数的参数,这是因为带有额外字段的对象将是Patrial<Target>
返回类型的子类型,所以它不会像你希望的那样失败。然后使用该类型计算一些错误的返回类型,如果有额外的字段。
计算错误类型的类型级函数如下:
在这里,你检查如果你取Source的所有键并从中排除Target的所有键,结果是什么。如果有
never
,这意味着Source中没有额外的字段,你可以安全地返回你想要的类型。否则,返回“fail”类型void,这将导致编译错误。这将导致: