为什么在排除扩展接口时,TypeScript会给出`never`类型

3

我创建了一个函数来剥离对象的接口。然而,Typescript(版本3.2.2)现在声称该类型为never,而它应该是一个带有属性child的类型。

interface Child extends Parent {
    child: string
}

interface Parent {
    parent: string
}

const a: Child = { child: "", parent: "" }

const b = removeParent(a);

function removeParent<T extends Parent>(obj: T) {
    delete obj.parent;
    return obj as Exclude<T, Parent>;
}

// b is now type never...

这是有效的:

function removeParent<T extends Parent>(obj: T) {
    delete obj.parent;
    type Without<T, K> = Pick<T, Exclude<keyof T, K>>;
    return obj as Without<T, "parent">;
}

然而,我需要一个通用解决方案,不需要我写出要排除的类型。

1个回答

13
我认为您不需要使用Exclude<T, Parent>
实际上,Exclude 的定义是: type Exclude<T, U> = T extends U ? never : T 因此,在您的应用中,由于 T 扩展了 Parent,您的返回类型将返回never
我认为您真正想要的是: Pick<T, Exclude<keyof T, keyof Parent>> 这样,您就可以说“选择所有不在父类中存在的 T 属性”。
function removeOneAndTwo<T extends Parent>(obj: T): Pick<T, Exclude<keyof T, keyof Parent>> {
  delete obj.one;
  delete obj.two;
  return obj;
}

2
Exclude 的真正用途是从联合类型中移除分支。例如 Exclude<string|null|void, null|void>string,或者从 keyof 类型中排除元素,就像在这个答案中所示。 - Jesse Hallett
1
更好的写法是:Omit<T, Parent 的 keyof> - Lucas Kuhlemann

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接