#typescript
#typescript
Вопрос:
Я писал код, который выглядит примерно так:
function helloWorld(customName: string) {
return `Hello, ${customName}`;
}
const myName: string | null = null;
const isValidName = myName !== null;
if (isValidName) {
console.log(helloWorld(myName));
}
Если вы запустите этот код на игровой площадке TypeScript, вы увидите, что TypeScript пожалуется, что Argument of type 'null' is not assignable to parameter of type 'string'.
Но как это происходит? Этот код выполняется только тогда, когда isValidName
он соответствует действительности, и isValidName
может быть, только true
если myName
это не null
так. Следовательно, myName
string
здесь. Почему это не работает?
Ответ №1:
Насколько я понимаю, тот факт, что вы сохраняете результат myName !== null
в переменной isValidName
, заставляет TypeScript проверять это значение во время выполнения и вести себя соответствующим образом (поэтому вызов helloWorld(myName)
кажется незаконным, потому isValidName
что потенциально может быть либо true
или false
во время выполнения).
Однако, если вы измените проверку на
if (myName !== null) {
console.log(helloWorld(myName));
}
TypeScript сможет определить, что единственным возможным типом myName
может быть a string
в этих обстоятельствах.
Ответ №2:
То, как вы это написали, typescript видит isValidName
boolean
, что это константа, и все.
Вы, автор кода, знаете, что значение isValidName
указывает что-то о значении myName
, но typescript не учитывает взаимосвязь между двумя переменными.
Вы хотите, чтобы в вашем if
заявлении использовалась защита типа. По сути, защита типа — это логическое значение, вычисляемое во время выполнения, которое зависит от значения myName
и является ли логическим true
или false
предоставляет некоторую информацию, которая сужает определение типа myName
.
Как указал @falinsky, myName !== null
он подходит для защиты типа, если вы используете его внутри условия вашего if
оператора. Он говорит: «если это true
так, то myName
это не null
так».
Вы также можете создать isValidName
функцию as, которая проверяет имя и определяет, что это строка.
const isValidName = (name: string | null): name is string => {
return name !== null;
}
if (isValidName(myName)) {
console.log(helloWorld(myName));
}
Ответ №3:
Если вы хотите сохранить результат сужения isValidName
для дальнейшего использования и не хотите его повторно вычислять, вы можете создать служебную функцию, подобную этой
/**
* @param a The precomputed result
* @param _b The variable to be narrowed down
* @template T The type to which `_b` will be narrowed down to when `a` is true
*/
function typeCheck<T>(a: boolean, _b: any): _b is T {
return a
}
Используйте так
if (typeCheck<string>(isValidName, myName)) {
console.log(helloWorld(myName)); // string here
} else {
console.log(myName) // null here
}
Это может быть полезно при вычислении длинных выражений, таких как
if (
isLoneAvailableCapacity(feed) amp;amp;
(isAvailableCapacitySubbeamPath(link) || isAvailableCapacityConnectivityLegPath(link)) amp;amp;
toAvailableCapacityKey(feed.availableCapacity) === link.availableCapacityKey
) {
// do something
}
// snip....
// some more code
if (
isLoneAvailableCapacity(feed) amp;amp;
(isAvailableCapacitySubbeamPath(link) || isAvailableCapacityConnectivityLegPath(link)) amp;amp;
toAvailableCapacityKey(feed.availableCapacity) === link.availableCapacityKey
) {
// do something else
}
Его можно легко заменить
const isValidFeed = isLoneAvailableCapacity(feed) amp;amp;
(isAvailableCapacitySubbeamPath(link) || isAvailableCapacityConnectivityLegPath(link)) amp;amp;
toAvailableCapacityKey(feed.availableCapacity) === link.availableCapacityKey
if(typeCheck<Feed>(isValidFeed, feed)) {
// do something
}
// snip....
// some more code
if(typeCheck<Feed>(isValidFeed, feed)) {
// do something else
}
Ответ №4:
Другие ответы хорошо объясняют обходные пути, но не объясняют почему.
Простой факт заключается в том, что Typescript еще недостаточно сложен, чтобы понимать несколько зависимых переменных.
Очень возможно, что в будущем будут добавлены функции для этого. Нет причин, по которым это не могло бы сработать, но я полагаю, что это просто сложно.
Я надеюсь, что однажды это сработает, потому что это также упрощает некоторые вещи, которые я делаю.