如何在 TypeScript 中从通用局部构建目标对象?

4

我正在使用typescript@2.3.4。

我有一个目标对象:

interface MyTarget {
    a: string;
    b: string;
    c: string;
    d: string;
}

我希望使用泛型创建多个部分对象的转换。

其中一个这样的转换可能如下所示:

const convert = <T extends object>(t: T): MyTarget => {
    return {
        c: "c",
        d: "d",
        ...t,
    };
};

然而,这会转化为:

error TS2698: Spread types may only be created from object types.

即使我将泛型 T 定义为 object,我仍然需要注意以下问题。我想起了有一个 Partial 类型,因此我尝试了以下代码:
const convert = (partial: Partial<MyTarget>): MyTarget => {
    return {
        c: "c",
        d: "d",
        ...partial,
    };
};

Partial类型使所有属性都变为可选项,但我不需要这样,并且现在会抛出错误:

src/Partial.ts(14,5): error TS2322: Type '{ a?: string; b?: string; c: string; d: string; }' is not assignable to type 'MyTarget'.
  Property 'a' is optional in type '{ a?: string; b?: string; c: string; d: string; }' but required in type 'MyTarget'.

我希望创建一个实例,MyTarget 的每个字段都设置为必需项。我想保持类型安全,这就是为什么我不想这样做的原因,即使它可以工作:

const convert = (partial: Partial<MyTarget>): MyTarget => {
    return {
        c: "c",
        d: "d",
        ...partial,
    } as MyTarget; // loses type checks, really don't want to
};
2个回答

1

我认为你正在使用较旧版本的TS(在新版本中,展开表达式已经正确地进行了类型化)。

不管这个,真正的问题是对象字面量可能不是一个完整的MyTarget。你的代码将允许这个调用。

convert({a : "" })// return value is not really MyTarget since it will not contain b

您真正需要的是参数为MyTarget,除了cd之外。
interface MyTarget {
    a: string;
    b: string;
    c: string;
    d: string;
}
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
const convert = (t: Omit<MyTarget, 'c' | 'd'>) : MyTarget => {
    return {
        c: "c",
        d: "d",
        ...t,
    };
};

@k0pernikus 嗯...所以真的很老(指1年以上),我相信有一个适用于旧版本的Omit版本。你现在使用的是哪个版本? - Titian Cernicova-Dragomir
@k0pernikus 这里有一个旧版本的 Omit,应该是一个无缝替换,但我还没有测试过:http://ideasintosoftware.com/typescript-advanced-tricks/ - Titian Cernicova-Dragomir
链接的省略类型并没有按照我的预期行事:https://stackoverflow.com/questions/54535539/how-to-create-an-omit-type-for-tsc2-3 - k0pernikus
@k0pernikus 的创造性解决方案,如果你不介意为了获取类型而付出额外的运行时间开销。我想我已经被映射和条件类型宠坏了 :) - Titian Cernicova-Dragomir
1
我们的项目仍在使用2.3版本,所以我并不介意额外的运行时间等内容。我接受性能影响,因为这样可以为未来升级提供另一个理由 ;) - k0pernikus
显示剩余2条评论

0

我选择了 Qwertiy的解决方案

interface XYZ {
  x: number;
  y: number;
  z: number;
}

declare var { z, ...xy }: XYZ;

type XY = typeof xy; // { x: number; y: number;}

对于 tsc@2.3 完美运行。


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