Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
4.2k views
in Technique[技术] by (71.8m points)

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

I need to create an object of the following type:

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 (i.e. without using any)?

Bonus Question: What is a good way to initialize an object of type: type FuncWithA = ((string)=>void) & { a: string }?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I would recommend using Object.assign(), which TypeScript's standard library represents as returning an intersection type of the form you want. 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]. If you are okay with readonly [number, number, number] then you can use a const assertion:

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():

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 func(x: string) {
    console.log(x);
}
func.a = "foo"; // no error
funcWithA = func; // that works

Playground link to code


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...