按成员类型排除类型

Exclude type by member type

我有一个函数可以处理没有数据到达的情况,否则它会调用回调来处理实际数据。

我使用 Typescript 2.8.3。

我试过这种方法,但是不行:

interface Result { data: string | null; }

function doStuff(
    input: Result,
    cb: (str: Exclude<Result, {data: null}>) => void
): void {
    if (input.data) {
        cb({data: input.data});
    }
}

doStuff({data: "x"}, (result) => {
    alert(result.data.length); // TS2532: Object is possibly 'null'
});

我必须保留 Result 接口 因为它是由某些 GQL 库生成的代码。此解决方案有效,但对我来说不可能:

interface VoidResult { data: null; }
interface NonVoidResult { data: string; }
type Result = VoidResult | NonVoidResult;
function doStuff(
    data: Result,
    cb: (str: NonVoidResult) => void
): void { ... }

实际的结果对象不是字符串而是一个复杂的对象类型,将来甚至可能会发生变化。因此,像 cb: (str: string) => void 这样写回调也没有用。

有没有办法从对象成员为空的类型中删除?

Result 的类型不是联合,它的类型有一个联合成员。您需要从 data 属性:

中排除 null
interface Result { data: string | null; }

function doStuff(
    input: Result,
    cb: (str: { data: Exclude<Result['data'], null> }) => void
): void {
    if (input.data) {
        cb({data: input.data});
    }
}

doStuff({data: "x"}, (result) => {
    alert(result.data.length); // ok
});

您甚至可以创建从特定类型成员中排除 null 的类型。如果您的界面有更多成员,这会很有用:

interface Result { data: string | null; }
type RemoveNullFrom<T, TKey extends keyof T> = Pick<T, Exclude<keyof T, TKey>> & {
    [P in TKey] : Exclude<T[P], null>    
}
function doStuff(
    input: Result,
    cb: (str: RemoveNullFrom<Result, 'data'>) => void
): void {
    if (input.data) {
        cb({data: input.data});
    }
}

doStuff({data: "x"}, (result) => {
    alert(result.data.length); // ok
});