It looks like TypeScript sees that myList is string[], so myList[7] is detected to be of type string.
Although it's assignable to something of type string | undefined, TypeScript determines that it can't be undefined, so it automatically narrows the type of foo to string only.
If you wanted this to produce an error, you would have to type myList as Array<string | undefined>:
let myList: Array<string | undefined> = require('something')
let foo: string | undefined = myList[7]
console.log(foo);
foo.includes('') // Error
foo.length // Error
If you want TypeScript to understand that accessing past the end of the array will result in undefined, use a tuple type instead:
let myList: [string, string] = require('something')
let foo = myList[7]
Then foo is typed as undefined, because it's past the length of the array.
If you don't know in advance how many elements the array has, the easiest way to get TypeScript to throw the error you want is really to type the array as Array<string | undefined>, since accessing any numeric index of the array may produce a string or undefined, despite the fact that the array's own-property values are all strings.