0

I'm trying to create a generic function that returns a random item in an array and properly forwards type information using Typescript 2.6.2.

function sample<T>(array: T[]) : T {
  const index = Math.floor(Math.random() * array.length);
  return array[index];
}

const obj1 = sample([1, 'a', Symbol('sym')]);
// const obj1: number | string | symbol

const obj2 = sample([1, 'a', Symbol('sym'), {}]);
// const obj2: {}

const obj3 = sample([1, 'a', Symbol('sym'), {a: 'a'}]);
// const obj3: number | string | symbol | {a: string}

The type signatures for obj1 and obj3 are fine, but for some reason the empty object in the 2nd example causes obj2's signature to get replaced with {}.

  1. Can you explain why obj2's signature becomes {}?
  2. Is there a way to work around this?
2
  • I can't reproduce this; I'm getting obj2 to be {} in all versions of TS I've tested. Commented Jan 20, 2018 at 1:46
  • Sorry, you're right @jcalz, I should have said {}. I'll edit to correct. I'm still confused, though. Commented Jan 22, 2018 at 18:27

1 Answer 1

1

When infering the type, TypeScript tries to find the lowest common subtype of the expressions, which usually results in a union type. So if you have:

const x = [a, b, c]

where a, b and c are of type A, B and C respectively, the infered type of x is A | B | C. This is exactly what happens for obj1 and obj3. But why obj2 has type {}:

The answer is that TypeScript has structural typing, meaning that if type A has all the properties of type B, an instance of A is assignable to B. {} denotes an empty object type, and since it has no member, any other object type is a subtype of this type. Therefore, the infered type number | string | symbol | {} is effectively equal to {}. (Recall that A | B when A is a subset of B is B).

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

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.