简体   繁体   English

如何使用 TypeScript 中的额外属性初始化数组 object?

[英]How to initialize an array object with extra properties in TypeScript?

I need to create an object of the following type:我需要创建以下类型的 object:

type ArrayWithA = [number, number, number] & { a: string };

I do this as follows:我这样做如下:

const obj : any = [1, 2, 3];
obj.a = "foo";
const arrayWithA : ArrayWithA = obj as ArrayWithA;

Question: What is a better way to accomplish this (ie without using any )?问题:有什么更好的方法来完成这个(即不使用any )?

Bonus Question: What is a good way to initialize an object of type: type FuncWithA = ((string)=>void) & { a: string } ?奖励问题:什么是初始化 object 类型的好方法: type FuncWithA = ((string)=>void) & { a: string }

Use Object.assign !使用Object.assign

The return type of Object.assign is just the intersection of the types of its arguments, so you can compose these hybrid objects by listing out their parts and combining at once, rather than adding additional properties after the fact (which often requires type casts, as you note). Object.assign的返回类型只是其 arguments 类型的交集,因此您可以通过列出它们的部分并立即组合来组合这些混合对象,而不是事后添加额外的属性(这通常需要类型转换,正如你所注意到的)。

So for some of your examples, you might do so like this:因此,对于您的一些示例,您可能会这样做:

type ArrayWithA = [number, number, number] & { a: string };

// Try like so:
// The cast is needed as otherwise it will be inferred as number[].
const obj2 = Object.assign([1, 2, 3] as [number, number, number], {a: "foo"}); // obj2 has type: [number, number, number] & { a: string } and is assignable to ArrayWithA.

// Same for functions!
type FuncWithA = ((arg: string) => void) & { a: string };

const f1 = Object.assign((s: string) => {}, {a: "foo"}) // f1 has type: ((s: string) => void) & { a: string } and is assignable to FuncWithA.

Playground Link. 游乐场链接。

I would recommend using Object.assign() , which TypeScript's standard library represents as returning an intersection type of the form you want.我建议使用Object.assign()TypeScript 的标准库将其表示为返回所需形式的交集类型。 There's a little bit of a wrinkle in that it's not easy to get the compiler to just infer that an array literal will be a tuple of the exact type [number, number, number] .有一点问题是,要让编译器仅仅推断出数组文字将是确切类型的元组[number, number, number]并不容易。 If you are okay with readonly [number, number, number] then you can use a const assertion :如果您对readonly [number, number, number]没问题,那么您可以使用const断言

type ArrayWithA = readonly [number, number, number] & { a: string };
const arrayWithA: ArrayWithA = Object.assign([1, 2, 3] as const, { a: "foo" });

Otherwise there are various tricks you can use:否则,您可以使用各种技巧:

type ArrayWithA = [number, number, number] & { a: string };

const arr: [number, number, number] = [1, 2, 3]; // annotate extra variable
let arrayWithA: ArrayWithA = Object.assign(arr, { a: "foo" });

// type assertion
arrayWithA = Object.assign([1, 2, 3] as [number, number, number], { a: "foo" });

// helper function
const asTuple = <T extends any[]>(arr: [...T]) => arr;
arrayWithA = Object.assign(asTuple([1, 2, 3]), { a: "foo" });

For functions, you can do the same thing with Object.assign() :对于函数,你可以用Object.assign()做同样的事情:

type FuncWithA = ((x: string) => void) & { a: string }
let funcWithA: FuncWithA = Object.assign(
  (x: string) => console.log(x.toUpperCase()), 
  { a: "foo" }
);

But you could also just use a function statement and add the property later, since TypeScript 3.1 introduced expando functions :但是您也可以只使用 function 语句并稍后添加属性,因为 TypeScript 3.1 引入了expando 函数

function func(x: string) {
    console.log(x);
}
func.a = "foo"; // no error
funcWithA = func; // that works

Playground link to code Playground 代码链接

I would go with something like:我会 go 类似:

type ArrayWithA = [number, number, number] & { a: string };
namespace ArrayWithA {
  export function of(a: string, ...rest: [number, number, number]): ArrayWithA {
    const o = rest as ArrayWithA;
    o.a = a;
    return o;
  }
}

const arrayWithA = ArrayWithA.of('a', 1, 2, 3);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM