Reputation: 71
I want the typescript compiler to throw an 'Object is possibly 'undefined'' error when trying to directly access any element of the array if the array is not pre-checked for emptiness, so that you always have to check that element for undefined, for example, using an optional chaining
If it is pre-checked that the array is not empty, then you need to be able to access its elements as usual, without the need to check its elements for undefined
I need this in order to be sure that the array is not empty, so if it is empty, then access to any of its elements will immediately return undefined then chaining will not continue and there will be no possible errors like cannot read property of undefined
How do i do this?
Code example, maybe it will make my question clearer
interface Element {
a: {
aa: string;
bb: string;
};
b: {
aa: string;
bb: string;
};
}
const element: Element = {
a: { aa: "aa", bb: "bb" },
b: { aa: "aa", bb: "bb" },
};
type ElementArray = Element[];
const array: ElementArray = [element, element];
const emptyArray: ElementArray = [];
const getFirstAWithoutLengthCheck = (array: ElementArray) => {
return array[0].a; // i want the typescript compiler to throw an 'Object is possibly 'undefined'' error here
};
const getFirstAWithLengthCheck = (array: ElementArray) => {
if (array.length) {
return array[0].a; // shouldn't be any errors
}
return null;
};
const getFirstAOptChaining = (array: ElementArray) => {
return array[0]?.a; // shouldn't be any errors
};
// will throw error cannot read property a of undefined, so we need to use
// optional chaining or length check in this function, but typesript is not requiring it
console.log(getFirstAWithoutLengthCheck(array)); // aa
console.log(getFirstAWithoutLengthCheck(emptyArray)); // crash!
// checking array length, access to first element should work as usual, no errors
console.log(getFirstAWithLengthCheck(array)); // aa
console.log(getFirstAWithLengthCheck(emptyArray)); // null
// optional chaining, no errors
console.log(getFirstAOptChaining(array)); // aa
console.log(getFirstAOptChaining(emptyArray)); // undefined
Upvotes: 3
Views: 2067
Reputation: 2201
As commented by @Roberto Zvjerković, you need to use noUncheckedIndexedAccess compiler flag.
Playground (The link has noUncheckedIndexedAccess
flag turned on).
However, you need to use instead of if (array.length)
, you need to do if (array[0])
. It is because, even if the length is non-zero, it does not ensure that the elements are "non-undefined". If the array were array = [undefined]
, it should have given runtime error. It is irrespective of the type of array if it can contain undefined
or not.
Upvotes: 3
Reputation: 2220
I managed to make TypeScript throw an error in the first example and not throw an error in the third one but it sadly gives you the undefined error in the second example. Hope this helps you:
interface Element {
a: {
aa: string;
bb: string;
};
b: {
aa: string;
bb: string;
};
}
const element: Element = {
a: { aa: "aa", bb: "bb" },
b: { aa: "aa", bb: "bb" },
};
type ElementArray = [] | [Element] | [Element, ...Element[]];
const array: ElementArray = [element, element];
const emptyArray: ElementArray = [];
const getFirstAWithoutLengthCheck = (array: ElementArray) => {
return array[0].a; // i want the typescript compiler to throw an 'Object is possibly 'undefined'' error here
};
const getFirstAWithLengthCheck = (array: ElementArray) => {
if (array.length) {
return array[0].a; // shouldn't be any errors
}
return null;
};
const getFirstAOptChaining = (array: ElementArray) => {
return array[0]?.a; // shouldn't be any errors
};
// will throw error cannot read property a of undefined, so we need to use
// optional chaining or length check in this function, but typesript is not requiring it
console.log(getFirstAWithoutLengthCheck(array)); // aa
console.log(getFirstAWithoutLengthCheck(emptyArray)); // crash!
// checking array length, access to first element should work as usual, no errors
console.log(getFirstAWithLengthCheck(array)); // aa
console.log(getFirstAWithLengthCheck(emptyArray)); // null
// optional chaining, no errors
console.log(getFirstAOptChaining(array)); // aa
console.log(getFirstAOptChaining(emptyArray)); // undefined
TypeScript playground Ignore the error on element, TypeScript playground thinks that element is a DOM element
Upvotes: 0