react-native 解析如何编写.d.ts声明文件

接上一篇《react-native 为本地js和开源库的js编写.d.ts声明文件》,本篇分析为在react-native中应用js文件,我是如何写声明文件 *.d.ts 的。

在学习Typescript时,关于如何编写声明文件。文档中提到,可参考、学习开源库中的源码声明。因此,源码中必然能给我们代码更大实践效果上的收获!

编写声明文件灵感分析从两个方面:

1,源码分析,node-modules/@Types/react-native是如何编写声明全局变量;
2,源码分析,node-modules/react-native-ui-lib 是如何编写声明文件的;
3,实操分析,对本地自己个写的js代码,是如何编写声明文件的;

分析源码node-modules/@Types/react-native

打开源码目录 [node-moduels/@Types/react-native](https://github.com/wix/react-native-ui-lib),结合react-native的编码习惯。可以发现 index.d.ts 必定是最终面向开发者使用的声明文件了。
在这里插入图片描述

// index.d.ts
  	...
... 代码省略...
  	...
//
// Prop Types
//
export const ColorPropType: React.Validator<string>;
export const EdgeInsetsPropType: React.Validator<Insets>;
export const PointPropType: React.Validator<PointPropType>;
export const ViewPropTypes: React.ValidationMap<ViewProps>;

declare global {
    interface NodeRequire {
        (id: string): any;
    }

    var require: NodeRequire;

    /**
     * Console polyfill
     * @see https://facebook.github.io/react-native/docs/javascript-environment.html#polyfills
     */
    interface Console {
        error(message?: any, ...optionalParams: any[]): void;
        info(message?: any, ...optionalParams: any[]): void;
        log(message?: any, ...optionalParams: any[]): void;
        warn(message?: any, ...optionalParams: any[]): void;
        trace(message?: any, ...optionalParams: any[]): void;
        debug(message?: any, ...optionalParams: any[]): void;
        table(...data: any[]): void;
        groupCollapsed(label?: string): void;
        groupEnd(): void;
        group(label?: string): void;
        disableYellowBox: boolean;
        ignoredYellowBox: string[];
    }

    var console: Console;

    /**
     * This contains the non-native `XMLHttpRequest` object, which you can use if you want to route network requests
     * through DevTools (to trace them):
     *
     *   global.XMLHttpRequest = global.originalXMLHttpRequest;
     *
     * @see https://github.com/facebook/react-native/issues/934
     */
    const originalXMLHttpRequest: any;

    const __BUNDLE_START_TIME__: number;
    const ErrorUtils: ErrorUtils;

    /**
     * This variable is set to true when react-native is running in Dev mode
     * Typical usage:
     * <code> if (__DEV__) console.log('Running in dev mode')</code>
     */
    const __DEV__: boolean;

    const HermesInternal: null | {};
}

然后则会发现声明全局对象的 declare global {}。结合我们平时使用过程中有用到打印日志的方法console.log('这里打印日志 - 声明:全局对象-全局变量')。可以确定console是已被声明的全局变量。那么我们个人应该怎么通过·global·扩展自己个的全局变量。
当然扩展全局变量,在Typescript这门技术语言中是有自己的一套系统定义的。中文文档有说道,在 npm 包或 UMD 库中扩展全局变量的方式。 而通过实践对比来看,在react-native中要对全局进行扩展变量和npm 包或 UMD 库中扩展全局变量的方式是一致的。如在这里对全局变量进行扩展,通过 —— declare global

// */namesp/index.d.ts
//
// Prop Types
// 
export {};
declare global {

    var gHeight: string | number;
    var gWidth: string | number;
}

如果 注释掉这行代码 export {}; 会有什么变化?export {}; 是做什么用的?
在这里插入图片描述

会发现有错误提示:Augmentations for the global scope can only be directly nested in external modules or ambient module declarations.ts(2669)[全局作用域的扩展只能直接嵌套在外部模块或环境模块声明中。ts(2669)]
外部模块的声明方式则是 export 方式。内部模块的声明方式是namespace方式。所以是提示我们在当前的index.d.ts声明文件中进行全局作用域的扩展,要以 export 方式进行声明使得index.d.ts声明文件的作用域成为外部模块。[用来告诉编译器这是一个模块的声明文件,而不是一个全局变量的声明文件。]

分析源码node-modules/react-native-ui-lib

声明文件的内容依照什么编写?

在这里插入图片描述
截图展示开源库react-native-ui-lib的目录结构。
其中图中看到 index.d.ts 是为该开源库所做的声明文件的总的对外输出。沿着这条线索追踪 ~ 选择export * from './components'; 进入可看到声明文件 *\components\index.d.ts

// */node_modules/react-native-ui-lib/typings/components/index.d.ts

export * from './ActionBar';
export * from './ActionSheet';
export * from './Avatar';
export * from './Badge';
export * from './Button';
export * from './Card';
... ...
export * from './Text';
export * from './Toast';
export * from './TouchableOpacity';
export * from './Tour';
export * from './View';
export * from './WheelPickerDialog';

在此选择较熟悉的组件 export * from './Toast'; 进入看源码

// */node_modules/react-native-ui-lib/typings/components/Toast.d.ts

import {ReactElement} from 'react';
import {
  GestureResponderEvent,
  ImageRequireSource,
  StyleProp,
  TextStyle
} from 'react-native';
import {BaseComponent} from '../commons';
import {ColorValue} from '../style/colors';
import {ButtonProps} from './Button';
import {BlurViewProperties} from '@react-native-community/blur';

export type ToastPosition = "relative" | "top" | "bottom";

export interface ToastProps {
  visible?: boolean;
  position?: ToastPosition;
  height?: number;
  backgroundColor?: ColorValue;
  color?: ColorValue;
  message?: string;
  messageStyle?: StyleProp<TextStyle>;
  icon?: ImageRequireSource;
  actions?: ReadonlyArray<ButtonProps>;
  onDismiss?: (event: GestureResponderEvent) => void;
  autoDismiss?: number;
  allowDismiss?: boolean;
  onAnimationEnd?: (visible: boolean) => void;
  renderContent?: (props: ToastProps) => ReactElement | ReactElement[] | null;
  centerMessage?: boolean;
  animated?: boolean;
  enableBlur?: boolean;
  blurOptions?: BlurViewProperties;
  zIndex?: number;
}

export class Toast extends BaseComponent<ToastProps> {}

看 Toast.d.ts 该土司组件的声明文件,第38行,通过export class Toast extends BaseComponent<ToastProps> {} 在声明文件中使用 export 导出,然后在使用方 import 导入,应用这些类型声明。且在类型声明上,继承的父类BaseComponent具有泛型约束<ToastProps> , ts语言使用关键字 interface 进行接口类型定义,规范组件Toast的props属性即作类型检查。等同于js语言组件的PropTypes进行类型检查

// */Greeting .js

 import PropTypes from 'prop-types';
 import {Text} from 'react-native';
 class Greeting extends React.Component {
  static propTypes = {
   name: PropTypes.string,
   requiredFunc: PropTypes.func.isRequired,
   requiredAny: PropTypes.any.isRequired,
   // 枚举类型。
   optionalEnum: PropTypes.oneOf(['News', 'Photos']),

  };
  render() {
    return (
      <Text>Hello, {this.props.name}</Text>
    );
  }
}

声明文件作用就是为ts语言环境引用js语言代码 。 既然是有关Toast.d.ts声明文件,那么必然会有对应的Toast.js文件存在。查!
在这里插入图片描述
因此 Ts目录*/node-modules/react-native-ui-lib/typings/components/Toast.d.ts 对应
Js目录*/node-modules/react-native-ui-lib/src/components/toast/index.js

// */src/components/toast/index.js
import _ from 'lodash';
import PropTypes from 'prop-types';
import React from 'react';
import {AccessibilityInfo, findNodeHandle, StyleSheet, Animated, Easing, ActivityIndicator} from 'react-native';
import {
  ThemeManager,
  Assets,
  Colors,
  Typography,
  BorderRadiuses,
  PureBaseComponent,
  View,
  Image,
  Button,
  Text
} from 'react-native-ui-lib';

// Create animated view base on uilib view for the safeArea support
const AnimatedView = Animated.createAnimatedComponent(View);
const COLOR = Colors.white;

/**
 * @description: A toast component
 * @example: https://github.com/wix/react-native-ui-lib/blob/master/demo/src/screens/componentScreens/ToastsScreen.js
 */
export default class Toast extends PureBaseComponent {
  static displayName = 'Toast';
... ... 
  render() {
     ... ...
    );
  }
}

... ...
}

观察Ts的声明文件 Toast.d.ts 发出疑问 —— interface ToastProps{} 为什么在这里写?它其中的元素属性又是怎么来的?
回答这个问题前,首先我们要明白。xx.d.ts 文件是用来声明 index.js 文件的。暴露 index.js 文件中的组件、属性、方法等给tsx文件以供使用。
所以,xx.d.ts 中编写的声明内容完全是以index.js作为依照来编写的。皮之不存,毛将焉附,没有Toast的index.js,就无从编写Toast.d.ts声明文件。通过Ts声明文件Toast.d.ts 与 Js的Toast组件 index.js文件对比,便可以证明这一点! 比如,Toast.d.ts 中的属性约束接口ToastProps

//   */Toast.d.ts 
... ... 
export interface ToastProps {
  visible?: boolean;
  position?: ToastPosition;
  height?: number;
  backgroundColor?: ColorValue;
  color?: ColorValue;
  message?: string;
  messageStyle?: StyleProp<TextStyle>;
  icon?: ImageRequireSource;
  actions?: ReadonlyArray<ButtonProps>;
  onDismiss?: (event: GestureResponderEvent) => void;
  autoDismiss?: number;
  allowDismiss?: boolean;
  onAnimationEnd?: (visible: boolean) => void;
  renderContent?: (props: ToastProps) => ReactElement | ReactElement[] | null;
  centerMessage?: boolean;
  animated?: boolean;
  enableBlur?: boolean;
  blurOptions?: BlurViewProperties;
  zIndex?: number;
}
...   ...

对应于Toast的Js文件内容的类型检查属性propTypes 如下

//   */Toast/index.js
... ...
static propTypes = {
    /**
     * Whether to show or hide the toast
     */
    visible: PropTypes.bool,
    /**
     * The position of the toast. 'top' or 'bottom'.
     */
    position: PropTypes.oneOf(['top', 'bottom']),
    /**
     * custom zIndex for toast
     */
    zIndex: PropTypes.number,
    /**
     * The background color of the toast
     */
    backgroundColor: PropTypes.string,
    /**
     * the toast content color (message, actions labels)
     */
    color: PropTypes.string,
    /**
     * the toast message
     */
    message: PropTypes.string,
    /**
     * should message be centered in the toast
     */
    centerMessage: PropTypes.bool,
    /**
     * a left icon
     */
    icon: PropTypes.number,
    /**
     * a single action for the user
     */
    action: PropTypes.shape(Button.propTypes),
    /**
     * should show a loader (showDismiss must be false)
     */
    showLoader: PropTypes.bool,
    /**
     * callback for dismiss action
     */
    onDismiss: PropTypes.func,
    /**
     * number of milliseconds to automatically invoke the onDismiss callback
     */
    autoDismiss: PropTypes.number,
    /**
     * show dismiss action (right 'X' button)
     */
    showDismiss: PropTypes.bool,
    /**
     * callback for end of component animation
     */
    onAnimationEnd: PropTypes.func,
    /**
     * render a custom view that will appear permanently above or below a Toast,
     * depends on the Toast's position, and animate with it when the Toast is made visible or dismissed
     */
    renderAttachment: PropTypes.elementType,
    /**
     * render a custom loader component instead of the default when passing showLoader
     */
    customLoader: PropTypes.func
  };
  ... ...
声明文件的内容怎么暴露对外?

export class Toast extends BaseComponent<ToastProps> {}
分析:以npm 包的声明文件方式进行声明 —— export class *** *** 。
声明文件中不能有实现,因此我们会经常看到这种格式:

export type XXX = 'default' | 'hue' ;
export interface XXX{
  value?: number;
 ...
}
export class XXX extends XX<T> {}

而且会发现该开源库中的组件,全以这格式作文件声明!在研究声明文件Toast.d.ts时发现有这样的一些代码

// */node_modules/react-native-ui-lib/typings/components/Toast.d.ts

import {ReactElement} from 'react';
import {
  GestureResponderEvent,
  ImageRequireSource,
  StyleProp,
  TextStyle
} from 'react-native';
import {BaseComponent} from '../commons';
import {ColorValue} from '../style/colors';
import {ButtonProps} from './Button';
... ...

第12行代码,import {ButtonProps} from './Button'; 进入查看源码,和Toast.d.ts一样正常定义接口约束和导出模块export interface ButtonProps extends TextProps {...},并且./Button 文件可以在定义声明文件的目录./node-modules/typings 中找到。 但是import {ColorValue} from '../style/colors';就大不相同,因为 …/style/colors 文件不在声明文件的目录 ./node-modules/typings 中,而是在Js源码文件 ./node-modules/src/中。 说明这种类型的js文件是可以在ts文件中被使用。而不必然不能在tsx文件中使用。 这种引用方式很特别且很实用和方便。且看colors.js源码

// node_modules\react-native-ui-lib\src\style\colors.js

import _ from 'lodash';
//@ts-ignore
import Color from 'color';
import tinycolor from 'tinycolor2';
import { colorsPalette } from './colorsPalette';
//@ts-ignore
import ColorName from './colorName';
export class Colors {
    ... ...
    /**
     * Load custom set of colors
     * arguments:
     * colors - map of keys and colors values e.g {dark10: '#20303C', dark20: '#43515C'}
     */
    loadColors(colors) {
        _.forEach(colors, (value, key) => {
            this[key] = value;
        });
    }
    ... ...
const TypedColors = Colors;
const colorObject = new TypedColors();
colorObject.loadColors(colorsPalette);
export default colorObject;

动态的将 import { colorsPalette } from './colorsPalette';

// node_modules\react-native-ui-lib\src\style\colorsPalette.js
const colorsPalette = {
    // DARKS TODO: deprecate and use greys
    dark10: '#20303C',
    dark20: '#43515C',
    dark30: '#66737C',
   ... ...
    // WHITE,
    white: '#FFFFFF',
    black: '#000000'
};
// For Eslint --fix
const extraFixColorsMap = {
    black: 'black',
    white: 'white',
    '#000': 'black',
    '#fff': 'white'
};
export { colorsPalette, extraFixColorsMap };

以方式import {ColorValue} from '../style/colors';添加成为Toast.d.ts 中的联合类型 。
截至此时,该开源库有bug尚未解决,bug问题不是本blog研究的方向。这里简要提一嘴。如toast的index.js中类型检查的属性renderAttachment与Toast.d.ts声明文件中renderContent的命名不一致、不一样。在使用时会发现不起作用,因此需要我们手动修改回来。

开源组件使用

在组件使用上,使用 import {Toast, Button} from 'react-native-ui-lib';由于在配置属性上会有报错提示,警告!但是不影响使用。警告提示import {Toast, Button} from 'react-native-ui-lib';
在这里插入图片描述
效果展示:
在这里插入图片描述

实操分析,为本地js编写声明文件

问题回顾:声明文件index.d.ts 这类文件叫做声明文件,为提供ts语言兼容js语言而存在 —— 即在ts中使用js的代码。结合项目实际开发中,我们会用到自定义的全局变量js第三方开源库本地js代码 。以上已经分析过了前2类使用方式,第三类本地js代码若要提供给ts使用,怎么编写声明文件?

大致有几类这里总结下

  • declare var 声明全局变量
  • declare function 声明全局方法
  • declare class 声明全局类
  • declare enum 声明全局枚举类型
  • declare namespace 声明(含有子属性的)全局对象
  • interface 和 type 声明全局类型

这几类读起来我们肯定能很容易就理解的。但是如何结合js文件才是关键!
那么我就开始举例说明了 ~
下面描述的声明文件方式,和上面总结的几类是对应着进行举例描述的。
编写本地将要使用的js文件 jsmodule.js

// */jsmodule.js

/**
 * 手写声明文件,使用js程序 
 */


/**
 * 手写声明文件,使用js程序 
 */

export const DEVICE_VERSION = 'Android 版本 - 10';

export function express(params){
  console.log('function - express 方法');
  if(typeof params == 'number'){
    return 'function - express number方法 ->' + params;

  } else if(typeof params == 'string'){

    return 'function - express string方法 ->' + params;
  } else {
    
    return 'function - express no-param方法' ;
  }
}

export class StringChecker {
   deviceHeight = '1920px';
   devoceWidth = '1080px';

   checkerEmpety = ()=>{
     return 'hello empety'+this.deviceHeight + '-' +this.devoceWidth;
   }
}

编写为ts使用js的声明文件jsmodule.d.ts

// */jsmodule.d.ts

declare const DEVICE_VERSION: string;
declare const express: (params?:string | number)=>string;
declare class StringChecker{
  deviceHeight: string | number;
  checkerEmpety(): string;
}
export {StringChecker, DEVICE_VERSION, express};

react-native中的.tsx文件中具体使用
在 npm 包的声明文件中,使用 declare 不再会声明一个全局变量,而只会在当前文件中声明一个局部变量。

// */screens/OnlineContact.tsx

import React from 'react';
import {
  View,
  Text,
  Image,
} from 'react-native';
import { TouchableOpacity } from 'react-native-gesture-handler';
import DeviceConfs from '../confs/DeviceConfs';
import ImgConfs from '../../src/confs/ImgConfs';
import {StringChecker, DEVICE_VERSION, express} from '../libs/js-module/jsmodule';
import LettersOnlyValidator from '../libs/namesp/LettersOnlyValidator';

interface OnlineContactProps {
  id: string;
  schecker: StringChecker;
}
interface OnlineContactState {
  tabIndex: number;
}
export default class OnlineContact extends React.Component<OnlineContactProps, OnlineContactState>{

  schecker = new StringChecker();
  constructor(props: OnlineContactProps){
    super(props);
    this.state = {
      tabIndex: 0
    }
  }
  
  render(){
    
    return <View style={{flex:1, alignItems:'center', backgroundColor: 'white'}}>
      {/* 标题栏 */}
        <View style={{width: DeviceConfs.sWidth, height: 42, 
            flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between'}}>
            <TouchableOpacity onPress={()=>{this.props.navigation.pop()}} activeOpacity = {0.8}
              style={{flexDirection:'row', alignItems: 'center', width:DeviceConfs.sWidth * 0.3}}>
              <Image source={ImgConfs.ic_goback} resizeMode={'contain'} 
              style={{width: 38, height: 38}}/>
              <Text style={{color: '#444', fontWeight: 'bold', fontSize: 14, alignSelf: 'center', marginLeft: -6}}>{'返回'}</Text>
            </TouchableOpacity>
          <View style={{width:DeviceConfs.sWidth * 0.3, alignItems: 'center', justifyContent:'center'}}>
            <Text style={{color: '#333', fontWeight: 'bold', fontSize: 18}}>{'TS功能测试'}</Text>
          </View>
          <View style={{width:DeviceConfs.sWidth * 0.3}}/>
        </View>
        <View style={{height:4, width: DeviceConfs.sWidth, backgroundColor: '#f4f4f4'}}/>

        {/* 写入测试的代码 */}
        
        {/* 自定义声明文件使用本地js */}
        <View style= {{width:DeviceConfs.sWidth, height: DeviceConfs.sHeight ,
            padding: 30 ,alignItems: 'center'}}>
              <Text style={{fontSize: 16, color: '#e48723', alignSelf: 'flex-start'}}>
              {'自写声明文件&本地js - DEVICE_VERSION:'}{'\n'}{DEVICE_VERSION}
              </Text>
              <Text style={{fontSize: 16, color: '#e46c23', alignSelf: 'flex-start', marginVertical:15}}>
              {'自写声明文件&本地js - express:'}{'\n'}{express('中国大爱')}
              </Text>
              <Text style={{fontSize: 16, color: '#e44723', alignSelf: 'flex-start'}}>
              {'自写声明文件&本地js - StringChecker:'}{'\n'}{new StringChecker().checkerEmpety()}
              </Text>
        </View>

      </View>
  }
}

展示下使用之后的效果展示:
在这里插入图片描述
需要注意的一点是 在环境上下文中不允许初始化器。 即在声明文件中是不允许做变量赋值和方法、类的具体实现的。
在这里插入图片描述
需要注意的二点是 *.js 文件中,类似下面片段代码

// */StringChecker.js
export class StringChecker {
   deviceHeight = '1920px';
   ... ...

如果要在 class StringChecker 中的方法中引用,则需要用到上下文环境,如下'hello empety'+this.deviceHeight + '-' +this.devoceWidth;。否则会报错:找不到变量deviceHeight 和 devoceWidth。

// */StringChecker.js
export class StringChecker {
   deviceHeight = '1920px';
   devoceWidth = '1080px';

   checkerEmpety = ()=>{
     return 'hello empety'+this.deviceHeight + '-' +this.devoceWidth;
   }
}

上面描述了 变量(let、const和var)、方法(function)、类(class)的声明,还缺少了对象(namespace)、类型(interface 和 type) 和 枚举(枚举)的具体分析。
暂且不论 declare enum , 且分析declare namespace和interface 和 type的使用。

定义 *js 文件,以es6的语法糖方式进行编写

// */namesp/ZipCodeValidator.js

// const numberRegexp = /^[0-9]+$/;
export default class ZipCodeValidator {
    isAcceptable(s) {

        return "ZipCodeValidator - 使用export namespace 声明文件";
    }

    printZLCodeValidator(param){

        return {method:'国人', key:'都在议', value: param}
    }
}

之后,另定义一个 *.js 文件,引用js类ZipCodeValidator ,以es6的语法糖方式进行编写

// */namesp/LettersOnlyValidator.js

import ZipCodeValidator from "./ZipCodeValidator";

// const lettersRegexp = /^[A-Za-z]+$/;
class LettersOnlyValidator {
    isAcceptable(s) {
        return "LettersOnlyValidator - 使用export namespace 声明文件";
    }
}
LettersOnlyValidator.ZipCodeValidator = ZipCodeValidator;
export default LettersOnlyValidator;

这里边让我很惊艳的是这一行代码,因为之前从未使用过,且这种使用方式是从·react-native-ui-lib源码·中发现的
LettersOnlyValidator.ZipCodeValidator = ZipCodeValidator;
通过以上两个js文件的class类的定义及相引用,则在数据结构上会产生一个新的有层级的数据结构 ,因此也就很自然的对应上了命名空间namespace : 命名空间是为了提供逻辑分组和避免命名冲突

因此编写声明文件以提供ts文件使用,其中使用到了字符串索引类型,并以此来诠释了declare namespace 声明(含有子属性的)全局对象 interface 和 type 声明全局类型的使用。

// */namesp/LettersOnlyValidator.d.ts

declare class LettersOnlyValidator{
    isAcceptable(s?: string): string;
}
 
declare namespace LettersOnlyValidator {
    interface ZLCodeValidator {
        method:'国人'| number;
        key: '都在议' | number;
        value: string;
    }
    // interface 定义的接口约束 等同于下面 type定义的类型约束
    // type ZLCodeValidator = {
    //     method:'国人'| number;
    //     key: '都在议' | number;
    //     value: string;
    // };
    export class ZipCodeValidator{
        isAcceptable(s?: string): string|boolean;

        printZLCodeValidator(param: string): {[key: string]: ZLCodeValidator};
    }
}
export default LettersOnlyValidator;

并且在文件 *.d.ts 中,有看到

...
declare class LettersOnlyValidator
...
...
declare namespace LettersOnlyValidator
...

两者会进行声明合并,若以Java语言的语法进行解释的话,等同于Java中 ZipCodeValidator 是 LettersOnlyValidator的内部类。

此时应用到 *.tsx 中

// */screens/OnlineContact.tsx

import React from 'react';
import {
  View,
  Text,
  Image,
} from 'react-native';
import { TouchableOpacity } from 'react-native-gesture-handler';
import ImgConfs from '../../src/confs/ImgConfs';
import {StringChecker, DEVICE_VERSION, express} from '../libs/js-module/jsmodule';
import LettersOnlyValidator from '../libs/namesp/LettersOnlyValidator';

interface OnlineContactProps {
  id: string;
  schecker: StringChecker;
}
interface OnlineContactState {
  tabIndex: number;
}
export default class OnlineContact extends React.Component<OnlineContactProps, OnlineContactState>{

  schecker = new StringChecker();
  constructor(props: OnlineContactProps){
    super(props);
    this.state = {
      tabIndex: 0
    }
  }
  
  render(){
    
    return <View style={{flex:1, alignItems:'center', backgroundColor: 'white'}}>
      {/* 标题栏 */}
        <View style={{width: DeviceConfs.sWidth, height: 42, 
            flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between'}}>
            <TouchableOpacity onPress={()=>{this.props.navigation.pop()}} activeOpacity = {0.8}
              style={{flexDirection:'row', alignItems: 'center', width:DeviceConfs.sWidth * 0.3}}>
              <Image source={ImgConfs.ic_goback} resizeMode={'contain'} 
              style={{width: 38, height: 38}}/>
              <Text style={{color: '#444', fontWeight: 'bold', fontSize: 14, alignSelf: 'center', marginLeft: -6}}>{'返回'}</Text>
            </TouchableOpacity>
          <View style={{width:DeviceConfs.sWidth * 0.3, alignItems: 'center', justifyContent:'center'}}>
            <Text style={{color: '#333', fontWeight: 'bold', fontSize: 18}}>{'TS功能测试'}</Text>
          </View>
          <View style={{width:DeviceConfs.sWidth * 0.3}}/>
        </View>
        <View style={{height:4, width: DeviceConfs.sWidth, backgroundColor: '#f4f4f4'}}/>

        {/* 写入测试的代码 */}
        
        {/* 自定义声明文件使用本地js */}
        <View style= {{width:gWidth, height: gHeight ,
            padding: 30 ,alignItems: 'center'}}>
              <Text style={{fontSize: 16, color: '#e44723', alignSelf: 'flex-start'}}>
              {'自写声明文件&本地js - LettersOnlyValidator:'}{'\n'}
              {new LettersOnlyValidator.ZipCodeValidator().printZLCodeValidator('大美中国')['method']}
              {new LettersOnlyValidator.ZipCodeValidator().printZLCodeValidator('大美中国')['key']}
              {new LettersOnlyValidator.ZipCodeValidator().printZLCodeValidator('大美中国')['value']}
              </Text>
        </View>

      </View>
  }
}

然后看到对应效果展示
在这里插入图片描述

文章参考:
https://zh-hans.reactjs.org/docs/

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值