Eu escrevi este código
interface Foo {
abcdef: number;
}
let x: Foo | string;
if (x instanceof Foo) {
// ...
}
Mas o TypeScript me deu este erro:
'Foo' only refers to a type, but is being used as a value here.
Por que isso está acontecendo? Achei que isso instanceof
poderia verificar se meu valor tem um determinado tipo, mas o TypeScript parece não gostar disso.
javascript
typescript
instanceof
Daniel Rosenwasser
fonte
fonte
Foo | string
.Respostas:
O que está acontecendo
O problema é que
instanceof
é uma construção do JavaScript e, em JavaScript,instanceof
espera um valor para o operando do lado direito. Especificamente, nox instanceof Foo
JavaScript irá executar uma verificação de tempo de execução para ver seFoo.prototype
existe em qualquer lugar na cadeia de protótipos dex
.No entanto, no TypeScript,
interface
s não têm emit. Isso significa queFoo
nemFoo.prototype
existe nem em tempo de execução, portanto, este código irá falhar definitivamente.O TypeScript está tentando dizer que isso nunca funcionaria.
Foo
é apenas um tipo, não é um valor!"O que posso fazer em vez de
instanceof
?"Você pode examinar os protetores de tipo e os protetores de tipo definidos pelo usuário .
"Mas e se eu apenas mudasse de um
interface
para umclass
?"Você pode ficar tentado a mudar de um
interface
para umclass
, mas você deve perceber que no sistema de tipo estrutural do TypeScript (onde as coisas são principalmente baseadas na forma ), você pode produzir qualquer objeto que tenha a mesma forma de uma determinada classe:class C { a: number = 10; b: boolean = true; c: string = "hello"; } let x = new C() let y = { a: 10, b: true, c: "hello", } // Works! x = y; y = x;
Nesse caso, você tem
x
ey
que tem o mesmo tipo, mas se tentar usarinstanceof
em um deles, obterá o resultado oposto no outro. Então,instanceof
não vai realmente dizer muito sobre o tipo se você está aproveitando tipos estruturais à máquina.fonte
instanceof
funciona com classes, não interfaces. Pensei que isso precisava ser enfatizado.Fazer a verificação de tipo em tempo de execução com uma interface é usar protetores de tipo , se as interfaces que você deseja verificar têm propriedades / funções diferentes .
Exemplo
let pet = getSmallPet(); if ((pet as Fish).swim) { (pet as Fish).swim(); } else if ((pet as Bird).fly) { (pet as Bird).fly(); }
fonte
Duck
, você digita guarda, ele se tornaFish
, mas ainda sem exceção de tempo de execução quando você invocaswim()
. Sugiro que você crie 1 nível de interface comum (por exemploSwimmable
) e mova suasswim()
funções para lá, então digite guard ainda ficará bem com((pet as Swimmable).swim
.'swim' in pet
condição. Ele vai reduzi-lo a um subconjunto que tem de terswim
definido (ex:Fish | Mammal
)Daniel Rosenwasser pode estar certo e elegante, mas estou com vontade de fazer uma alteração à sua resposta. É totalmente possível verificar a instância de x, consulte o trecho de código.
Mas é igualmente fácil atribuir x = y. Agora, x não seria uma instância de C, pois y só tinha a forma de C.
class C { a: number = 10; b: boolean = true; c: string = "hello"; } let x = new C() let y = { a: 10, b: true, c: "hello", } console.log('x is C? ' + (x instanceof C)) // return true console.log('y is C? ' + (y instanceof C)) // return false
fonte