如何在打字稿中使用具有对象属性的数组

How can I use arrays with object properties in typescript

有没有办法在 typescript

中不使用 @ts-ignore 而使用具有对象属性的数组

假设我有这个函数,它会尝试将一个数组转换为一个带有属性 属性 的数组。这工作正常,除了他们是 @ts-ignore

    const addPropToArray = <T extends unknown>(x: T[]): T[] & {prop: number} => {
      //@ts-ignore
      const y: T[] & {prop: number} = [...x];
      y.prop = 3;
      return y
    };

显然我不能这样做

const x: string[] & {prop:number} = // what could go here

本身,这就是我考虑使用该函数的原因,但即便如此,该函数也必须具有 @ts-ignore.

具有对象属性的数组是不是一个糟糕的主意以至于打字稿没有尝试很好地支持它们,或者它们是我缺少的东西吗?

也许他们是这个可行的变体?

const x: string[] & {prop:number} = {...["a","b","c"], prop: 4}

显然这里的问题是它不再是一个数组。

编辑: 我意识到我可以直接转换值而不是使用 @ts-ignore 但那个门槛似乎不是最好的解决方案

Obviously I can't do this const x: string[] & {prop:number} = // what could go here

如果您分配自执行匿名函数的返回值,您就可以这样做。像这样的东西,例如:

interface ArrayProps {
    prop: number;
}

const x: string[] & ArrayProps = (() => {
    const xPartial: string[] & Partial<ArrayProps> = [];
    xPartial.prop = 3;

    return xPartial as string[] & ArrayProps;
})();

TypeScript Playground

我不确定是否有办法在没有 type assertion, though. Adding a custom type guard 的情况下执行此操作,而不是类型断言需要考虑类型保护失败的路径,所以 x 会结束也可以是 undefined 或其他,具体取决于该路径的处理方式。

The Object.assign(target, source) method copies the enumerable own properties from a source object onto the target object and returns the augmented target. And the TypeScript standard library typings for this method 看起来像:

interface ObjectConstructor {
    assign<T, U>(target: T, source: U): T & U;
}

意味着它将操作建模为生成 source 和原始 target 类型的 intersection,这正是您要找的!

所以你可以这样写addPropToArray():

const addPropToArray = <T extends unknown>(x: T[]): T[] & { prop: number } => {
  return Object.assign([...x], { prop: 3 });
};

没有type assertions or //@ts-ignore comments.

请注意,如果您确实必须在类型断言和//@ts-ignore之间做出选择,选择类型断言。他们都有能力阻止错误,但都不安全。但是类型断言的范围有限,它告诉编译器将某个值视为某种类型,而 //@ts-ignore 只是抑制错误消息,并且可能会产生奇怪的非本地副作用。使用类型断言就像按下烟雾探测器上的“临时静音”按钮,这样您就可以安静地做饭,而使用 //@ts-ignore 就像完全移除烟雾探测器的电池。


无论如何,让我们确保它有效:

const z = addPropToArray(["a", "b"]);
console.log(z) // ["a", "b"]
console.log(z.prop) // 3

看起来不错。

Playground link to code