'typescript asserts if returns not null (with typeguard)

I am trying to check some property of a variable with a regular Expression and if that matched, I want the type of that variable be inferred to a more specific type.

I have an example in the typescript playground:

type xN = `x${number}`;
const reg = new RegExp("x([0-9]+)");

function check(s:string):RegExpMatchArray | null /* asserts s is xN*/{
  return s.match(reg);
}

declare const test :string;
const match = check(test);

if(match){
  // test should be of type xN now
  match.groups // use that non-null match variable, too...

}

Is there a way to do that with one function in (TS 4.5.4)? If not, how would you do it neatly?



Solution 1:[1]

Base on Single responsibility principle, I don't think you should do both in a function. It makes your application more complicated.

Instead of that, you can break it into two functions like that:

type xN = `x${number}`;
const reg=new RegExp("x([0-9]+)");

function isXn(s: string): s is xN {
  return true
}

function check(s: xN):RegExpMatchArray {
  return s.match(reg)!; // !: since xN is always match reg
}

declare const test :string;

if(isXn(test)){
  //test is xN now
  const match = check(test);
  match.groups // use that non-null match variable, too...
}

Solution 2:[2]

If you just want to know if the string is xN

type xN = `x${number}`;
const reg=new RegExp("x([0-9]+)");

function check(input:string): input is `${string}${xN}${string}` {
  return !!input.match(reg)
}

let checkStr:string
if (check(checkStr)) {
  checkStr
  // ^? `x${number}`(xN)
} else {
  checkStr
  // ^? string
}

If you know exactly the string (string is constant), it allows you to know the correct string.

function getValue<T extends string>(input:T){
  const reg=new RegExp("x([0-9]+)");
  const match = input.match(reg)
  if(match) return match[1] as T extends `x${infer W}` ? W : null
  else return null
}

const knowStr1 = "x356363"
const value1 = getValue(knowStr1)
//    ^? "356363"

const knowStr2 = "hi"
const value2 = getValue(knowStr2)
//    ^? null

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Long Nguyen Duc
Solution 2