when assigning a variable of type unknown
to another variable, we should go through the type checking of the unknown
variable but how can TypeScript understand this specific condition? looks like it's returning a boolean
but I think it's more complicated :
let first: unknown = 5;
let second: number;
const result = typeof first === 'number';
if(result){
second = first; // error : Type 'unknown' is not assignable to type 'number'
}
if(typeof first === 'number'){
second = first; // no errors
}
CodePudding user response:
To guarantee that values have the correct types at compilation time, TypeScript uses type checking. The type of the value that is stored in a variable is returned as a string when you use the typeof operator on that variable. In this instance, typeof returns "number" first.
Because the condition result in the first if statement is a boolean variable, TypeScript only verifies the type of result and not the type of first.
The expression typeof first === 'number' in the second if clause provides a boolean value that indicates whether the type of first is "number." The type of the expression cannot be determined at compile time by TypeScript because it is unclear what type first is. However, the expression returns true when the condition is evaluated at runtime, proving that the type of first is in fact a "number". Because first has a known type of number, the assignment second = first is permitted in this instance.
Thus, when the expression typeof first === 'number' is evaluated at runtime, TypeScript essentially validates the type of first within the second if statement.
CodePudding user response:
TypeScript added support for indirect expression type narrowing in TypeScript 4.4 after PR #44730 was added in June 2021. In the notes introducing this feature, Anders Hejsberg mentions the limitations of this feature (emphasis and formatting mine):
Narrowing through indirect-references occurs only when:
- the conditional-expression or discriminant-property access is declared in a
const
variable declaration with no type annotation, and...- the reference being narrowed is one-of:
- a
const
variable or- a
readonly
property or- a parameter for which there are no assignments in the function body.
In your case your let first: unknown = 5;
variable's assign cannot be used with this feature because it's a let
local variable instead of a const
local.
So if you change the code to use const first
instead of let first
, then it works:
const first: unknown = 5;
let second: number;
const result = ( typeof first === 'number' );
if( result ) {
second = first; // OK!
}
if( typeof first === 'number' ) {
second = first; // OK!
}