如何基于超类型的对象创建子类型的对象?

时间:2019-06-06 13:15:13

标签: typescript

我有一个超类型的对象compactUser,并且我想以类型安全的方式基于对象detailedUser创建一个子类型的对象compactUser

我有一个可行的解决方案,在下面的代码中detailedUser1,但是我想针对更复杂的场景提供更灵活的方法(沿着detailedUser2行)。

(对不起,这看起来是一个基本的打字稿问题,我确实在寻找解决方案,但最终在这里提出了问题。)

code

interface CompactUser {
    id: number
}

interface DetailedUser {
    id: number
    name: string
    sex: string
}

const compactUser: CompactUser = {id: 1}

const detailedUser1: DetailedUser = {
    ...compactUser,
    name: 'nume',
    sex: 'm',
}

// I don't like this; it's more flexible, but error prone
const detailedUser2 = compactUser as DetailedUser

// ups, I set `sex`, but forgot about `name`
detailedUser2.sex = Math.random() > 0.5 ? 'f' : 'm'

// not ok - I access `name` and there's no typescript error
console.log(detailedUser2.name)

1 个答案:

答案 0 :(得分:0)

  

我有一个可行的解决方案,在下面的代码中detailedUser1

您的操作方式就是您的操作方式,如您的示例中那样使用扩展符号:

const detailedUser1: DetailedUser = {
    ...compactUser,
    name: 'nume',
    sex: 'm',
};

...或Object.assign

const detailedUser1: DetailedUser = Object.assign(
    {},
    compactUser,
    {
        name: 'nume',
        sex: 'm',
    }
};

在这些中,我想说传播是最清晰,最常见的。请注意,这两个属性均保留compactUser all 属性,但是在您的情况下compactUser仅具有适合DetailedUser的属性,因此很好。

如果存在更复杂的场景,您可能希望将它们放在可重用的函数中,但它们在本质上将是相似的。

  

我想更灵活一些(沿detailedUser2行)...

您的detailsUser2根本不会做任何事情来使对象适合该类型,它只是向TypeScript断言它是必需的类型。从那时起,该对象与它的类型信息不同步,因为它没有namesex,但是它的类型表明它确实有:

console.log("sex" in detailedUser2); // false, but the type says it has to be true

Live Copy

这就是为什么您必须做与detailedUser1一样的事情。

如果要使用更新的类型信息重用同一对象,可以执行以下操作:

const detailedUser2: DetailedUser = Object.assign(compactUser, {name: "x", sex: "f"});

例如,提供缺少的属性。这样就可以更新compactUser。 (同样,如果compactUser的属性DetailedUser不存在,即使类型表明它们不存在,它们也会存在;但是,在您的示例中情况并非如此。)

detailedUser1和上面的Object.assign的优点之一是,如果您忘记了属性,TypeScript会告诉您:

const detailedUser2: DetailedUser = {...compactUser, {name: "x"});
//    ^^^^^^^^^^^^^-- Property 'sex' is missing in type 'CompactUser & { name: string; }' but required in type 'DetailedUser'.

const detailedUser2: DetailedUser = Object.assign(compactUser, {name: "x"});
//    ^^^^^^^^^^^^^-- Property 'sex' is missing in type 'CompactUser & { name: string; }' but required in type 'DetailedUser'.

Live Copy