Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I do a type assertion for a variable in Typescript that should be valid for a whole block/function?

I have a state variable that is of type null | SOME_TYPE. But some functions expect it to be SOME_TYPE and those functions are 100% sure that the state variable will be SOME_TYPE when they run.

Can I type cast/assert a variable that will be valid for a whole function scope?

Example:

const [myState,setMyState] = useState<null | SOME_TYPE>(null);

function doSomething() {
  // THIS FUNCTION NEEDS myState TO BE SOME_TYPE
  // IT'S 100% GUARANTEED THAT WHEN IT RUNS, myState WILL BE SOME_TYPE

  // IT WILL ACCESS MULTIPLE PROPERTIES OF MY STATE
  console.log(myState.someProp as SOME_TYPE);
  console.log(myState.someOther as SOME_TYPE);
  console.log(myState.another as SOME_TYPE);
}

Instead of multiple and repetitive type casts, can I do a "block" type assertion (without creating a new variable)?

Example:

function doSomething() {

  // myState as SOME_TYPE
  // THE IDEA IS THAT INSIDE THIS WHOLE BLOCK myState IS CONSIDERED TO BE SOME_TYPE

  console.log(myState.someProp);
  console.log(myState.someOther);
  console.log(myState.another);
}

Is there a syntax or a proposal for that?

like image 324
cbdeveloper Avatar asked Nov 02 '25 08:11

cbdeveloper


2 Answers

I believe that new variable is acceptable solution, but your other option is an user-defined type guard.

Contrary to new variable with cast, the preconditon will be checked in runtime.

function isSomeType(x: null | SOME_TYPE): x is SOME_TYPE {
  return x !== null;
} 

function doSomething() {
  if (isSomeType(myState)) {
    console.log(myState.stateSomeType);
    console.log(myState.someOther);
    console.log(myState.another);
  }
}

Also, as your type is SOME_TYPE | null, not null guard will work as well:

function doSomething() {
  if (myState !== null) {
    console.log(myState.stateSomeType);
    console.log(myState.someOther);
    console.log(myState.another);
  }
}

Playground link

like image 196
Lesiak Avatar answered Nov 03 '25 23:11

Lesiak


You can do that in multiple ways

function doSomething() {
    if (!myState) return; // Will return if myState is null
   
    // myState is not null for the rest of the function
    // Since it could only be null or SOME_TYPE then it must be SOME_TIME
    console.log(myState.someProp);
    console.log(myState.someOther);
    console.log(myState.another);
}

Another way is create another variable that is cast as SOME_TYPE

function doSomething() {
    // This cast is basically telling the compiler "shut up, I know what I am doing"
    // It's up to you to ensure the correctness and make sure myState is SOME_TYPE
    const myVar = myState as SOME_TYPE;
   
    console.log(myVar.someProp);
    console.log(myVar.someOther);
    console.log(myVar.another);
}

You can also use a Type guard. When your type is SOME_TYPE|null, you only need to check that myState is truthy or return from function if it is falsy as in the first code snippet above.

If you have myState being of type SOME_TYPE|ANOTHER_TYPE. A simple truthy check will not be enough. You can use a type guard.

function isSomeType(val: SOME_TYPE|ANOTHER_TYPE): val is SOME_TYPE {
    // do a check here to ensure that val is SOME_TYPE
    // For example you can check for the presence of a property that is in SOME_TYPE and not ANOTHER_TYPE
    return typeof val === 'object' && typeof ((val as SOME_TYPE).someProp) === 'string';
}

function doSomething() {
    // Before the call myState is SOME_TYPE|ANOTHER_TYPE
    if (!isSomeType(myState)) return;
    // After call myState is SOME_TYPE

    console.log(myState.someProp);
    console.log(myState.someOther);
    console.log(myState.another);
}
like image 33
Sherif Elmetainy Avatar answered Nov 03 '25 21:11

Sherif Elmetainy



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!