Item 25: Understand Evolving Types
May 10, 2024 ยท View on GitHub
Things to Remember
- While TypeScript types typically only refine, the types of values initialized to
null,undefined, or[]are allowed to evolve. - Recognize and understand this construct where it occurs, and use it to reduce the need for type annotations in your own code.
- For better error checking, consider providing an explicit type annotation instead of using evolving types.
Code Samples
function range(start: number, limit: number) {
const nums = [];
for (let i = start; i < limit; i++) {
nums.push(i);
}
return nums;
// ^? const nums: number[]
}
function range(start: number, limit: number) {
const nums = [];
// ^? const nums: any[]
for (let i = start; i < limit; i++) {
nums.push(i);
// ^? const nums: any[]
}
return nums;
// ^? const nums: number[]
}
const result = [];
// ^? const result: any[]
result.push('a');
result
// ^? const result: string[]
result.push(1);
result
// ^? const result: (string | number)[]
let value;
// ^? let value: any
if (Math.random() < 0.5) {
value = /hello/;
value
// ^? let value: RegExp
} else {
value = 12;
value
// ^? let value: number
}
value
// ^? let value: number | RegExp
let value = null;
// ^? let value: any
try {
value = doSomethingRiskyAndReturnANumber();
value
// ^? let value: number
} catch (e) {
console.warn('alas!');
}
value
// ^? let value: number | null
function range(start: number, limit: number) {
const nums = [];
// ~~~~ Variable 'nums' implicitly has type 'any[]' in some
// locations where its type cannot be determined
if (start === limit) {
return nums;
// ~~~~ Variable 'nums' implicitly has an 'any[]' type
}
for (let i = start; i < limit; i++) {
nums.push(i);
}
return nums;
}
function makeSquares(start: number, limit: number) {
const nums = [];
// ~~~~ Variable 'nums' implicitly has type 'any[]' in some locations
range(start, limit).forEach(i => {
nums.push(i * i);
});
return nums;
// ~~~~ Variable 'nums' implicitly has an 'any[]' type
}