Example 1
const myNumber = _.sample([1, 2, 3]);
// Expected type: number
// Actual type: number
Example 2
const arr = [1, 2, 3]
const myNumber = _.sample(arr);
// Expected type: number
// Actual type: number | undefined
Why is Typescript giving the type number | undefined in the second case, but not the first case?
This is happening because in one case the length of the array is known, and in the other it is not. If the length might be 0, then
undefinedis a possible output.When you do
const arr = [1, 2, 3], the type onarrisnumber[]. That means it's an array of numbers which can grow and shrink. You and I can see that it's not going to shrink to 0-length before the next line, but the type information doesn't include that knowledge. So when it gets passed into sample, the types say that undefined is a possible result.When you create and use the array in the exact same spot, as in
_.sample([1, 2, 3]);, typescript is able to assume a stricter type because it knows how it is being used. The type is inferred to be[number, number, number], ie a tuple of length 3, and therefore an element will definitely be returned.If you want to make this happen with the array being on a separate line, you'll need to tell typescript you want a stricter type on
arr. The simplest way to do this is withas const, which tells typescript you won't be changing this array:You can see the type definitions for
samplehere: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/lodash/common/collection.d.ts#L1641 . The tuple case is handled by this type:And the array case is handled by this type: