接上一篇《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>
}
}
然后看到对应效果展示