0

I need a type/interface to define a property that can be object or an array. The problem with typescript | operator is that if I use it I will have to explicitly check each time if the variable is array or not but I always know if its an object or an array. So instead I ended up using as SomeType or as SomeType[]. What I want is to not have to do it.

So current idea is to create a mixture of object and array, so that instead of array checks or "as" assertions I will have to add ?. everywhere.

My current solution is

interface _Array<T> extends Array<T | undefined> {}
type ArrayORObject<T> = Partial<T> & Partial<_Array<T>>;

Which almost works but the only issue is that now I'm getting "Index signature for type 'number' is missing in type SomeObject", seems that it requires objects to have Array index signature ([index: number]), but I can't figure out if its possible to have optional index signature.

Edit: Thanks for suggesting "satisfies" but bumping TS to beta version not really an option rn. adding call to makeOrder() isn't much better then creating some function that will check if array.

Better example TS Playground

4
  • 1
    Seems like an XY problem. The right type is probably SomeType | SomeType[] and your problem is having to write as SomeType or as SomeType[] in places; can you show us examples of that? Changing to Partial<SomeType> & Partial<SomeType[]> is almost certainly going to make things worse and not better. Commented Nov 8, 2022 at 19:29
  • @jcalz added an example. its not a big proble initiallty but I have multiple levels of nested object so I have to write "as" or check if it's an array a lot. so just having .? on every property would be much cleaner and easier. Commented Nov 8, 2022 at 20:07
  • You say: "but I always know if its an object or an array". How? - is the problem limited to object literals (as in example code)? Commented Nov 8, 2022 at 20:39
  • Given that example, I would suggest using satisfies (or similar) like Lesiak does. You are throwing away information the compiler could use to help you. If this does not meet your needs, could you edit again to show why not? Commented Nov 8, 2022 at 20:49

2 Answers 2

2

You have object literals order1 and order2. You know that in order1 there is only one burger, but in order2 there is an array of burgers. Unfortunately this information is lost when you give them explicit type order (with an union).

If you drop explicit type the type of your constant is precise, but nothing guarantees that it matches order interface.

TS 4.9 adds satisfies keyword to solve this situation:

const order1 = {
    main: { meat: 'beef' }
} satisfies order;

TS 4.9 solution in playground

Fortunately, you dont have to use TS 4.9 - you can use the fact that functions have strong type inference:

function makeOrder<T extends order>(o: T): T {
  return o;
}

const order1 = makeOrder({
    main: { meat: 'beef' }
});

TS 4.8 solution in playground

Sign up to request clarification or add additional context in comments.

3 Comments

OP is doing this purposely to demonstrate the problem. OP wants to use the type as if it were T & T[] instead of having to check if it's an array or not every time they use it. See their response to jcalz in the comments under the question.
@caTS I asked for clarification under OP - I believe this solution is enough for the demonstrated problem (object literals) - precise type is known.
I think this is the right answer to the underlying problem, assuming the example code is indicative of it.
0

a) convert that to always-array enter image description here

b) use the value inside if where you check its type enter image description here

code

1 Comment

Please don't use images of code. You should just copy/paste the code from the playground. Also, this doesn't answer the question. Read OP's response to jcalz in the comments.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.