網站搜尋

typescript - 有人可以向我解釋這段程式碼中的 'as never' 是做什麼用的嗎?


正如標題所說,我對這段程式碼中 'as never' 的意思感到困惑。我讀到它應該表示從不發生的事或排除其他類型,但我不太明白為什麼它會以下面程式碼的這種方式被使用。

import { View, Button, Text, StyleSheet, FlatList, TouchableOpacity, Image } from 'react-native'
import React from 'react'
import { useNavigation } from '@react-navigation/native'

const data = [
  {
    id: 1,
    title: 'Google Search',
    screen: 'MapScreen',
  },
  {
    id: 2,
    title: 'I\'m Feeling Lucky',
    screen: 'MapScreen',
  }
]

const NavOptions = (props: NavProps) => {
  const navigation = useNavigation();
  return (
    <FlatList
      data={data}
      keyExtractor={(item) => item.id}
      horizontal
      renderItem={({ item }) => (
        <View style={styles.container}>
          <TouchableOpacity
            onPress={() => props.term && navigation.navigate(item.screen as never, {
              term: props.term,
            } as never)}
            style={styles.button}>
            <Text style={styles.text}>{item.title}</Text>
          </TouchableOpacity>
        </View>
      )}
    />
  )
}

const styles = StyleSheet.create({
  container: {
    padding: 10,
  },
  button: {
    backgroundColor: "#f8f9fa",
    padding: 10,
  },
  text: {
    color: "black",
    textAlign: "center",
  },
});

type NavProps = {
  term: string;
}

export default NavOptions

答案#1

這段代碼簡直是錯的。

你對 never 的理解大致是正確的:它是一種沒有有效值的類型,通常出現在不相容類型的交集;它表示不可達的代碼、邏輯上不可能的情況以及無法完全計算的表達式。一個典型的例子是那些拋出異常而不是正常返回的函數:

function raiseRangeErr(e: string): never {
    throw new RangeError(e);
}

function div(a: number, b: number): number {
    return b !== 0 ? a / b : raiseRangeErr("division by zero");
}

never 有一個獨特的屬性,即這種類型的表達式可以賦值給任何其他類型。這是可行的,因為由於 never 沒有值,特別是它沒有可能不屬於目標類型的值。

撰寫那段程式碼的程式設計師可能想懶惰地利用這個屬性來壓制關於不可賦值類型的錯誤。從類型理論的角度來看,這是不正確的:程式碼中有 never 的部分應該是無法到達的,但問題中的程式碼顯然完全不是這樣。

無論如何,最好避免使用類型斷言;如果你可以簡單地移除那些斷言而不產生任何錯誤,那就這麼做。如果最終必須使用類型斷言,請使用與當前情況特定的類型。在最壞的情況下,使用 as any。唯一可以勉強接受 as never 的情況是呼叫一個你知道永遠不會返回的函數,但你缺乏能夠捕捉到這一點的類型定義。舉一個牽強的例子:

function raiseRangeErr(e: string): unknown {
    throw new RangeError(e);
}

function div(a: number, b: number): number {
    return b !== 0 ? a / b : raiseRangeErr("division by zero") as never;
}

即便如此,更新你的類型定義仍然是較為可取的。