Я написал этот код
interface Foo {
abcdef: number;
}
let x: Foo | string;
if (x instanceof Foo) {
// ...
}
Но TypeScript дал мне эту ошибку:
'Foo' only refers to a type, but is being used as a value here.
Почему это происходит? Я думал, что это instanceof
может проверить, имеет ли мое значение данный тип, но TypeScript, похоже, это не нравится.
javascript
typescript
instanceof
Даниэль Розенвассер
источник
источник
Foo | string
.Ответы:
Что происходит
Проблема в том, что
instanceof
это конструкция из JavaScript, а в JavaScriptinstanceof
ожидает значение для правого операнда. В частности, вx instanceof Foo
JavaScript выполняется проверка времени выполнения, чтобы увидеть,Foo.prototype
существует ли где-нибудь в цепочке прототиповx
.Однако в TypeScript у
interface
s нет emit. Это означает, что во время выполненияFoo
неFoo.prototype
существует и не существует, поэтому этот код определенно не сработает.TypeScript пытается сказать вам, что это никогда не сработает.
Foo
это просто тип, а вовсе не значение!"Что я могу сделать вместо
instanceof
?"Вы можете изучить защиты типов и защиты типов, определяемые пользователем .
"Но что, если я просто перейду с А
interface
на Аclass
?"У вас может возникнуть соблазн переключиться с a
interface
на aclass
, но вы должны понимать, что в системе структурных типов TypeScript (где вещи в основном основаны на форме ) вы можете создать любой объект, который имеет ту же форму, что и данный класс: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;
В этом случае у вас есть
x
и,y
которые имеют один и тот же тип, но если вы попытаетесь использоватьinstanceof
один из них, вы получите противоположный результат на другом. Такinstanceof
что особо не расскажу вам о типе, если вы пользуетесь преимуществами структурных типов в TypeScript.источник
instanceof
работает с классами, а не интерфейсами. Мысль, которую нужно подчеркнуть.Для проверки типов во время выполнения с помощью интерфейса используется защиты типов , если интерфейсы, которые вы хотите проверить, имеют разные свойства / функции.
пример
let pet = getSmallPet(); if ((pet as Fish).swim) { (pet as Fish).swim(); } else if ((pet as Bird).fly) { (pet as Bird).fly(); }
источник
Duck
, вы набираете guard, которым он становитсяFish
, но по-прежнему не вызывает исключения во время выполненияswim()
. Предложите вам создать 1 уровень общего интерфейса (напримерSwimmable
) и переместитьswim()
туда свои функции, тогда тип guard по-прежнему будет хорошо выглядеть((pet as Swimmable).swim
.'swim' in pet
условие. Это будет сократить его до подмножества , который должен бытьswim
определен (например:Fish | Mammal
)Даниэль Розенвассер, может быть, прав и щеголь, но мне хочется внести поправку в его ответ. Вполне возможно проверить экземпляр x, см. Фрагмент кода.
Но так же легко присвоить x = y. Теперь x не был бы экземпляром C, поскольку y имел только форму 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
источник