如何将返回值分配给受约束的泛型类型

时间:2019-01-27 20:07:29

标签: typescript

我正在尝试键入一个函数,该函数具有共同的可选属性,并且需要基于传入的泛型类型而缺少的属性。

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'.

Playground here

编辑:我还想确保泛型类型为One |。二|三

这可能吗?有没有更好的方式考虑这一点?

2 个答案:

答案 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无法区分missingundefined,因此可以:

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) })

对于使用它的任何人都带有很大的免责声明,永远不要传递未定义的内容。在这种情况下哪个可行。