网站搜索

React-Native TypeScript:将变量传入样式表对象时出错


这是我正在使用的风格以及我如何使用它

style={styles.input(isPasswordSelected)}
const styles = StyleSheet.create({
  input: (isPasswordSelected: boolean) => ({
    height: 40,
    marginHorizontal: 20,
    marginVertical: 7,
    padding: 10,
    borderRadius: 10,
    backgroundColor: '#c9c9c9',
    borderWidth: 1,
    borderColor: isPasswordSelected ? '#458ae6' : 'transparent',
  }),
});

这通常在 JS 中可以正常工作,但在 TS 中我会收到这个错误

类型 '(isPasswordSelected: boolean) => { height: number; marginHorizontal: number; marginVertical: number; padding: number; borderRadius: number; backgroundColor: string; borderWidth: number; borderColor: string; }' 不能分配给类型 'ViewStyle | TextStyle | ImageStyle'.ts(2322)

它似乎认为整个函数都是我的类型声明。

错误只出现在 IDE 中,代码运行正常。可能通过更新我的 tsconfig.json 可以解决

我尝试将类型改为 style typings,但无法消除错误

答案#1

函数不是 StyleSheet 的有效组成部分。有很多方法可以实现这一点。最常见的方法是在您的 StyleSheet 中静态地分配样式,然后在 JSX 中动态组合它们:

const styles = StyleSheet.create({
  input: {
    // everything except your borderColor style
  },
});

const YourScreen = () => {
  const isPasswordSelected = true; // replace with however you're getting this in your code
  return (
    <TextInput
      style={[styles.input, {
        borderColor: isPasswordSelected ? '#458ae6' : 'transparent',
      }]
      // ...

你也可以将你的样式做成一个返回 StyleSheet 的函数:

const styles = (isPasswordSelected: boolean) => StyleSheet.create({
  input: {
    // ... everything except your borderColor style
    borderColor: isPasswordSelected ? '#458ae6' : 'transparent',
  }),
});

答案#2

StylesSheet 不支持使用函数,但你可以改为使用对象或函数,并将返回值类型设置为以下类型之一:ViewStyle | TextStyle | ImageStyle

例如

const styles = {
    square: (size: number): ViewStyle => ({
        width: size,
        height: size,
    })
};

另一种方法是使用 StyleSheet.create < any > 来绕过此问题:

const styles = StyleSheet.create<any>({
  input: (isPasswordSelected: boolean): TextStyle => ({
    height: 40,
    marginHorizontal: 20,
    marginVertical: 7,
    padding: 10,
    borderRadius: 10,
    backgroundColor: isPasswordSelected ? 'yellow' : 'green',
    borderWidth: 2,
    borderColor: isPasswordSelected ? 'red' : 'transparent',
  }),
  text: {
    noterror: 40, // typescript not show error because of "<any>"
  }
});

但这样的话,你会失去其他属性的类型检查,查看演示:

https://snack.expo.dev/BDj-VZJm5

但正如我之前提到的,你可以使用对象或函数,并用这些类型之一来为返回值类型注解:ViewStyle | TextStyle | ImageStyle:

const text : ViewStyle = {
  backgroundColor:"white",
  ///anerror : 'error'
}

const styles = StyleSheet.create<any>({
  input: (isPasswordSelected: boolean): TextStyle => ({
    height: 40,
    marginHorizontal: 20,
    marginVertical: 7,
    padding: 10,
    borderRadius: 10,
    backgroundColor: isPasswordSelected ? 'yellow' : 'green',
    borderWidth: 2,
    borderColor: isPasswordSelected ? 'red' : 'transparent',
  }),
  text : text
});

而最好的方法是使用老派的方法

import * as React from 'react';
import {
  View,
  Text,
  StyleSheet,
  TextInput,
  ViewStyle,
  TextStyle,
  ImageStyle,
  StyleSheetProperties,
} from 'react-native';

const styles = StyleSheet.create<>({
  input: {
    height: 40,
    marginHorizontal: 20,
    marginVertical: 7,
    padding: 10,
    borderRadius: 10,
    backgroundColor: "green",
    borderWidth: 2,
  },
  borderColor458ae6: {
    borderColor: "red"
  },
  borderColorTransparent: {
    borderColor: "transparent"
  },
  container: {
    flex: 1,
    backgroundColor: "#ccc",
    justifyContent: "center",
    alignItems: "center"
  }
});

const inputIsPasswordSelected = (isPasswordSelected: boolean) => {
  return isPasswordSelected
    ? [styles.input, styles.borderColor458ae6]
    : [styles.input, styles.borderColorTransparent];
};

function App() {
  const [isPasswordSelected, setIsPasswordSelected] = React.useState(false);
  return (
    <View style={styles.container}>
      <Text>React Native App</Text>
      <TextInput
        secureTextEntry={true}
        style={inputIsPasswordSelected(isPasswordSelected)}
        onFocus={() => {
          setIsPasswordSelected(true);
        }}
        onBlur={() => {
          setIsPasswordSelected(false);
        }}
        value="abc"
      />
    </View>
  );
}

export default App;