typescript 如何将两个部分合并为一个完整的对象?

6l7fqoea  于 2023-06-24  发布在  TypeScript
关注(0)|答案(3)|浏览(153)

我有一个接口,需要所有的 prop 。但是,创建对象是一个两步过程。因此,我计划创建对象的2个Partial版本,然后将它们合并在一起以满足非局部接口。示例:

interface IComplete {
    a: string,
    b: string
}

const part1: Partial<IComplete> = {
    a: 'hello'
}

const part2: Partial<IComplete> = {
    b: 'world'
}

const together: IComplete = {
    ...part1,
    ...part2
}

即使together总是完整的,编译器也会抱怨:

Type '{ a?: string; b?: string; }' is not assignable to type 'IComplete'.
   Property 'a' is optional in type '{ a?: string; b?: string; }' but required in type 'IComplete'.

Playground
有没有推荐的方法来实现这一点?对于我的例子来说,重要的是接口IComplete * 不是 * 部分的,即属性a和B永远不会为null或undefined。

f0ofjuux

f0ofjuux1#

@RyanCavanaugh的回答很好。一种让类型推断工作的方法,同时仍然获得编译器的好处,确保part1part2Partial<IComplete>,就是使用如下的helper函数:

interface IComplete {
  a: string,
  b: string,
  c: (x: string) => number,
  d: (x: number) => string
}

// helper function
const asPartialIComplete = <T extends Partial<IComplete>>(t: T) => t;

const part1 = asPartialIComplete({
  a: 'hello',
  c: (x) => x.length
})

const part2 = asPartialIComplete({
  b: 'world',
  d: (x) => x + ""
});

const together: IComplete = {
  ...part1,
  ...part2
}

在上面的例子中,part1part2都被asPartialIComplete约束为有效的Partial<IComplete>对象(因此cd方法的参数分别推断为stringnumber)。但是part1part2的类型足够窄,编译器可以意识到typeof part1 & typeof part2IComplete
希望这也有帮助。祝你好运!

bn31dyow

bn31dyow2#

最简单的方法是删除类型注解,让类型推断来完成它的工作:

interface IComplete {
    a: string,
    b: string
}

const part1 = {
    a: 'hello'
}

const part2 = {
    b: 'world'
}

const together: IComplete = {
    ...part1,
    ...part2
}

这确实具有某些有害影响,例如part1part2中的函数表达式中的参数不会获得推断类型。
相反,你可以使用Pick--不幸的是,当使用这种方法时,你必须写出你从每种类型中选择的键:

interface IComplete {
    a: string,
    b: string,
    c: number
}

const part1: Pick<IComplete, "a"> = {
    a: 'hello'
}

const part2: Pick<IComplete, "b" | "c"> = {
    b: 'world',
    c: 43
}

const together: IComplete = {
    ...part1,
    ...part2
}
cld4siwp

cld4siwp3#

坦率地说,我不完全理解为什么typescript transpiler不允许这种语法。
但下面的代码可以绕过它,实现你想要的。

interface IComplete {
    a: string,
    b: string
}

const part1: Partial<IComplete> = {
    a: 'hello'
}

const part2: Partial<IComplete> = {
    b: 'world'
}

const together: IComplete = {
    ...part1,
    ...part2
} as IComplete

相关问题