我正在尝试键入一个函数,该函数具有共同的可选属性,并且需要基于传入的泛型类型而缺少的属性。
type Diff<T, U> = T extends U ? never : T
type DiffTypes<T, U> = { [Key in Diff<keyof T, keyof U>]: T[Key] }
interface Common {
name: string
}
interface One {
name: string
one: 1
}
interface Two {
name: string
two: 2
}
interface Three {
name: string
three: 3
}
type Numbers = One | Two | Three
const test = <T extends Numbers>(obj: Partial<Common> & DiffTypes<T, Common>): T => ({name: 'Default', ...obj})
我要
Type '{ name: string; } & Partial<Common> & DiffTypes<T, Common>' is not assignable to type 'T'.
编辑:我还想确保泛型类型为One |。二|三
这可能吗?有没有更好的方式考虑这一点?
答案 0 :(得分:1)
您的意思是:
type Omit<T, K extends keyof T> = {[P in Diff<keyof T, K>]: T[P]};
type Optional<T, U extends keyof T = keyof T> = Omit<T, U> & Partial<Pick<T, U>>;
const test = <T extends Numbers>(missing: Optional<T, keyof Common>): Common & typeof missing => ({
name: 'Default',
...missing
});
用法:
test<One>({ one: 1 });
test<One>({ one: 1, name: 'whooo' });
test<Two>({ two: 2 });
test<Three>({ three: 3 });
test<One>({ name: 'Bob' }) // Error
test<One>({ two: 2 }) // Error
答案 1 :(得分:0)
TLDR:Typescript不知道缺少属性和未定义属性之间的区别
问题实际上是Partial<Common>
参数类型中的obj
,它实际上被解释为:
{
name?: string | undefined
}
Typescript无法区分missing
和undefined
,因此可以:
test<One>({name: undefined})
对于参数类型有效。传递name
中的undefined
将覆盖默认名称,并且不符合返回类型的要求-导致错误消息。
跟踪此问题的相关问题可以在这里找到:https://github.com/Microsoft/TypeScript/issues/13195
我的解决方案 在打字稿可以做出这种区分之前,我选择了强制覆盖对象。
const test = <T extends Numbers>(
obj: Partial<Common> & DiffTypes<T, Common>,
): T => ({ name: 'Default', ...(obj as Common) })
对于使用它的任何人都带有很大的免责声明,永远不要传递未定义的内容。在这种情况下哪个可行。