typescript - Generiska typvakter som antar never


Den här koden:

class X<T> {
  isString(): this is X<string> {
    return true;
  }

  isNumber(): this is X<number> {
    return false;
  }
}

const x = new X();

if (x.isString()) {

} else if (x.isNumber()) { // Line 15

}

Vilket jag tycker semantiskt är korrekt, genererar detta fel:

meddelande: 'Egenskapen 'isNumber' finns inte på typen 'never'.' vid: '15,14'

Varför? Hur ska jag skriva if-batchen av meningar?

Svar #1

Typer i TypeScript är strukturella.

I ditt exempel är X<string> och X<number> strukturellt identiska - de har båda två typvaktmetoder, isString() och isNumber(), och inget annat. Så kompilatorn antar att om den första typvakten returnerar sant, måste den andra också returnera sant (eftersom de i verkligheten testar för samma typ), och else-grenen är oåtkomlig.

Så snart du får X att faktiskt bero på T, kompilerar det:

class X<T> {
  t: T;

  isString(): this is X<string> {
    return true;
  }

  isNumber(): this is X<number> {
    return false;
  }
}

const x = new X();

if (x.isString()) {

} else if (x.isNumber()) { // Line 15

}