У меня есть предикат типа:
// tslint:disable-next-line:no-any
const isString = (value: any): value is string {
return typeof value === 'string'
}
Это работает, но требует, чтобы я отключил линтер. Я бы предпочел это:
const isString = <T>(value: T): value is string {
return typeof value === 'string'
}
Таким образом, типом является не any, а вместо этого у нас есть по одной функции защиты типов для каждого типа, то есть по одной функции a -> Boolean для каждого a.
Typescript жалуется, что:
A type predicate's type must be assignable to its parameter's type. Type 'string' is not assignable to type 'T'.
Для меня это не имеет смысла ... Почему это должно иметь значение, какой у предиката типа тип?
Хм ... но позволять нам использовать (value: any) => value is string в качестве предиката типа - это еще хуже, не так ли? Я могу передать ему Date, если захочу.
Это немного другое. Использование T больше похоже на написание целого набора функций. Попробуйте написать защиту типа, определяемую пользователем, например (value: Date): value is string => { ... }, и вы поймете, что я имею в виду.
Хороший момент, универсальный означает «дайте мне по одной из каждой функции a -> Boolean», поэтому, если какая-либо из этих функций не существует, то универсального не существует. Хороший! Не могли бы вы написать ответ?






Защита определяемого пользователем типа выполняет проверку во время выполнения, чтобы определить, удовлетворяет ли значение определенного типа предикату типа.
Если нет связи между типом значения и типом в предикате типа, защита не будет иметь смысла. Например, TypeScript не допускает такой пользовательской защиты:
function isString(value: Date): value is string {
return typeof value === "string";
}
и вызовет эту ошибку:
[ts] A type predicate's type must be assignable to its parameter's type.
Type 'string' is not assignable to type 'Date'.
Значение Date никогда не будет string, поэтому защита бессмысленна: его проверка времени выполнения не нужна и всегда должна возвращать false.
Когда вы указываете общую, определяемую пользователем защиту типа, T может быть чем угодно, поэтому - как и в случае с Date - для некоторых типов защита типа не имеет смысла.
Если вы действительно не хотите использовать any, вы можете использовать вместо него пустой интерфейс - {}:
function isString(value: {}): value is string {
return typeof value === "string";
}
Если вы также хотите разрешить передачу значений null и undefined охраннику, вы можете использовать:
function isString(value: {} | null | undefined): value is string {
return typeof value === "string";
}
Что касается сообщения об ошибке, тип предиката должен быть назначен типу значения, поскольку защита типа используется для проверки того, действительно ли значение с менее конкретным типом является значением с более конкретным типом. Например, рассмотрим этого охранника:
function isApe(value: Animal): value is Ape {
return /* ... */
}
Ape можно присвоить Animal, но не наоборот.
Добавляя к принятому ответу, если вам понадобится использовать защиту типа от миксина, вы также получите эту ошибку, поскольку оператор is ведет себя не так, как implements.
interface Animal { ... }
interface Climber { ... }
interface Ape extends Animal, Climber { ... }
const isClimberMixin = (animal: Animal): animal is Climber => ...
Такой код не работает, потому что Climber не может быть назначен на Animal, поскольку он не расширяется от него.
Решение, если вы не можете избежать паттерна миксина, состоит в том, чтобы использовать тип объединения:
const isClimberMixin = (animal: Animal): animal is Animal & Climber => ...
Вместо этого вы можете использовать
(value: {}): value is string => { ... }. Что до ошибки, то она странная; это кажется обратным. Для меня было бы больше смысла назначатьTнаstring. Например, TypeScript должен знать, чтоDateникогда не будет назначенstring, поэтому такой предикат не имеет смысла.