Escribí este código
interface Foo {
abcdef: number;
}
let x: Foo | string;
if (x instanceof Foo) {
// ...
}
Pero TypeScript me dio este error:
'Foo' only refers to a type, but is being used as a value here.
¿Por qué está pasando esto? Pensé que instanceof
podría comprobar si mi valor tiene un tipo determinado, pero parece que a TypeScript no le gusta esto.
javascript
typescript
instanceof
Daniel Rosenwasser
fuente
fuente
Foo | string
.Respuestas:
Que esta pasando
El problema es que
instanceof
es una construcción de JavaScript, y en JavaScript,instanceof
espera un valor para el operando del lado derecho. Específicamente, enx instanceof Foo
JavaScript se realizará una verificación en tiempo de ejecución para ver siFoo.prototype
existe en algún lugar de la cadena de prototipos dex
.Sin embargo, en TypeScript, los
interface
s no tienen emisión. Eso significa que niFoo
niFoo.prototype
existen en tiempo de ejecución, por lo que este código definitivamente fallará.TypeScript está tratando de decirle que esto nunca podría funcionar.
Foo
es solo un tipo, ¡no es un valor en absoluto!"¿Qué puedo hacer en lugar de
instanceof
?"Puede buscar en los protectores de tipos y los protectores de tipos definidos por el usuario .
"¿Pero qué pasa si acabo de cambiar de una
interface
a unaclass
?"Es posible que tenga la tentación de cambiar de an
interface
a aclass
, pero debe darse cuenta de que en el sistema de tipos estructurales de TypeScript (donde las cosas se basan principalmente en la forma ), puede producir cualquier objeto que tenga la misma forma que una clase determinada: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;
En este caso, tiene
x
yy
tiene el mismo tipo, pero si intenta usarinstanceof
en cualquiera de los dos, obtendrá el resultado opuesto en el otro. Porinstanceof
lo tanto , no le dirá mucho sobre el tipo si está aprovechando los tipos estructurales en TypeScript.fuente
instanceof
funciona con clases, no con interfaces. Pensé que eso necesitaba ser enfatizado.Para realizar la verificación de tipos en tiempo de ejecución con una interfaz, se utilizan protectores de tipos , si las interfaces que desea verificar tienen propiedades / funciones diferentes .
Ejemplo
let pet = getSmallPet(); if ((pet as Fish).swim) { (pet as Fish).swim(); } else if ((pet as Bird).fly) { (pet as Bird).fly(); }
fuente
Duck
, escribe guard se convierteFish
, pero aún no hay excepción de tiempo de ejecución cuando invocasswim()
. Sugiero que cree 1 nivel de interfaz común (por ejemploSwimmable
) y mueva susswim()
funciones allí, luego type guard todavía se ve bien con((pet as Swimmable).swim
.'swim' in pet
condition. Será limitar la búsqueda a un subconjunto que tiene que haberswim
definido (por ejemplo:Fish | Mammal
)Daniel Rosenwasser puede tener razón y ser elegante, pero me apetece hacer una enmienda a su respuesta. Es completamente posible verificar la instancia de x, vea el fragmento de código.
Pero es igualmente fácil asignar x = y. Ahora, x no sería una instancia de C ya que y solo tenía la 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
fuente
Compruebe si su archivo es del tipo correcto. Las etiquetas no están permitidas en los archivos js, pero están permitidas en jsx
fuente