Leanote's Blog
I love Leanote!
Toggle navigation
Leanote's Blog
Home
Chrome
Git
Linux
Windows
Others
工具大全
VsCode
Expo
Html
JavaScript
Npm
Node
Mock
React-Native
React
TypeScript
小程序
插件
正则
Dva
Ant-Design-React
Umi
Vue
Vux
Ant-Design-Vue
Http
Java
flutter
开发小工具
About Me
Archives
Tags
在ReactNative中使用Typescript(二)
2019-11-14 07:46:18
3
0
0
admin
> 作者:花生毛豆- 来源:CSDN 原文:https://blog.csdn.net/s2096828/article/details/83744677 版权声明:本文为博主原创文章,转载请附上博文链接! # **编写第一个 TSX 组件** ``` import React from 'react' import ReactDOM from 'react-dom' const App = () => { return (<div>Hello world</div> ) } ReactDOM.render(, document.getElementById('root') ``` ### 上述代码运行时会出现以下错误 - `Cannot find module 'react'` - `Cannot find module 'react-dom'` 错误原因是由于 `React` 和 `React-dom` 并不是使用 TS 进行开发的,所以 TS 不知道 `React`、 `React-dom` 的类型,以及该模块导出了什么,此时需要引入 `.d.ts` 的声明文件,比较幸运的是在社区中已经发布了这些常用模块的声明文件 [DefinitelyTyped](http://definitelytyped.org/) 。 # **安装 `React`、 `React-dom` 类型定义文件** ## 使用 yarn 安装 yarn add @types/react yarn add @types/react-dom ## 使用 npm 安装 npm i @types/react -s npm i @types/react-dom -s # **有状态组件开发** 我们定义一个 App 有状态组件,`props`、 `state` 如下。 ### **Props** props | 类型 | 是否必传 :-: | :-: | :-: `color` | string | 是 `size` | string | 否 ### **State** props | 类型 :-: | :-: `count` | string ### 使用 TSX 我们可以这样写 ``` import * as React from 'react' interface IProps { color: string, size?: string, } interface IState { count: number, } class App extends React.Component<iprops, istate=""> { public state = { count: 1, } public render () { return (<div>Hello world</div> ) } } ``` ### TypeScript 可以对 JSX 进行解析,充分利用其本身的静态检查功能,使用泛型进行 `Props`、 `State` 的类型定义。定义后在使用 `this.state` 和 `this.props` 时可以在编辑器中获得更好的智能提示,并且会对类型进行检查。 那么 `Component` 的泛型是如何实现的呢,我们可以参考下 `React` 的类型定义文件 `node_modules/@types/react/index.d.ts`。 在这里可以看到 `Component` 这个泛型类, `P` 代表 Props 的类型, `S` 代表 `State` 的类型。 class Component<p, s=""> { readonly props: Readonly<{ children?: ReactNode }> & Readonly<p> state: Readonly<s> } ### 现在有了 `TypeScript` 我们可以通过将 `state` ,以及 `state` 下面的属性都设置为只读类型,从而防止直接更新 `state` 。 ``` import * as React from 'react' interface IProps { color: string, size?: string, } interface IState { count: number, } class App extends React.PureComponent<iprops, istate=""> { public readonly state: Readonly = { count: 1, } public render () { return ( </s></p><div><s>Hello world</s></div><s><s> ) } public componentDidMount () { this.state.count = 2 } } export default App ``` ### 此时我们直接修改 `state` 值的时候 TypeScript 会立刻告诉我们错误,`Error:(23, 16) TS2540: Cannot assign to 'count' because it is a constant or a read-only property.` 。 **** # **无状态组件开发** ### **Props** props | 类型 | 是否必传 :-: | :-: | :-: children | ReactNode | 否 onClick | function | 是 ### **SFC类型** 在 React 的声明文件中 已经定义了一个 SFC 类型,使用这个类型可以避免我们重复定义 children、 propTypes、 contextTypes、 defaultProps、displayName 的类型。 实现源码 node_modules/@types/react/index.d.ts 。 type SFC</s></s><p> = StatelessComponent</p><p> interface StatelessComponent</p><p> { (props: P & { children?: ReactNode }, context?: any): ReactElement | null; propTypes?: ValidationMap</p><p> contextTypes?: ValidationMap; defaultProps?: Partial</p><p> displayName?: string; } 使用 SFC 进行无状态组件开发。 import { SFC } from 'react' import { MouseEvent } from 'react' import * as React from 'react' interface IProps { onClick (event: MouseEvent): void, } const Button: SFC = ({onClick, children}) => { return ( </p><div> { children } </div><s><s> ) } export default Button **** # **事件处理** ### 我们在进行事件注册时经常会在事件处理函数中使用 `event` 事件对象,例如当使用鼠标事件时我们通过 `clientX`、`clientY` 去获取指针的坐标。 大家可以想到直接把 `event` 设置为 `any` 类型,但是这样就失去了我们对代码进行静态检查的意义。 function handleEvent (event: any) { console.log(event.clientY) } ### 试想下当我们注册一个 `Touch` 事件,然后错误的通过事件处理函数中的 `event` 对象去获取其 `clientY` 属性的值,在这里我们已经将 `event` 设置为 `any` 类型,导致 TypeScript 在编译时并不会提示我们错误, 当我们通过 `event.clientY` 访问时就有问题了,因为 `Touch` 事件的 `event` 对象并没有 `clientY` 这个属性。 ### 通过 `interface` 对 `event` 对象进行类型声明编写的话又十分浪费时间,幸运的是 React 的声明文件提供了 `Event` 对象的类型声明。 ## **Event 事件对象类型** 常用 Event 事件对象类型: - `ClipboardEvent` 剪贴板事件对象 - `DragEvent` 拖拽事件对象 - `ChangeEvent Change` 事件对象 - `KeyboardEvent` 键盘事件对象 - `MouseEvent` 鼠标事件对象 - `TouchEvent` 触摸事件对象 - `WheelEvent` 滚轮事件对象 - `AnimationEvent` 动画事件对象 - `TransitionEvent` 过渡事件对象 实例: import { MouseEvent } from 'react' interface IProps { onClick (event: MouseEvent): void, } `MouseEvent` 类型实现源码 `node_modules/@types/react/index.d.ts` 。 ``` interface SyntheticEvent { bubbles: boolean; /** * A reference to the element on which the event listener is registered. */ currentTarget: EventTarget & T; cancelable: boolean; defaultPrevented: boolean; eventPhase: number; isTrusted: boolean; nativeEvent: Event; preventDefault(): void; isDefaultPrevented(): boolean; stopPropagation(): void; isPropagationStopped(): boolean; persist(): void; // If you thought this should be `EventTarget & T`, see https://github.com/DefinitelyTyped/DefinitelyTyped/pull/12239 /** * A reference to the element from which the event was originally dispatched. * This might be a child element to the element on which the event listener is registered. * * @see currentTarget */ target: EventTarget; timeStamp: number; type: string; } interface MouseEvent extends SyntheticEvent { altKey: boolean; button: number; buttons: number; clientX: number; clientY: number; ctrlKey: boolean; /** * See [DOM Level 3 Events spec](https://www.w3.org/TR/uievents-key/#keys-modifier). for a list of valid (case-sensitive) arguments to this method. */ getModifierState(key: string): boolean; metaKey: boolean; nativeEvent: NativeMouseEvent; pageX: number; pageY: number; relatedTarget: EventTarget; screenX: number; screenY: number; shiftKey: boolean; } ``` `EventTarget` 类型实现源码 `node_modules/typescript/lib/lib.dom.d.ts` 。 interface EventTarget { addEventListener(type: string, listener: EventListenerOrEventListenerObject | null, options?: boolean | AddEventListenerOptions): void; dispatchEvent(evt: Event): boolean; removeEventListener(type: string, listener?: EventListenerOrEventListenerObject | null, options?: EventListenerOptions | boolean): void; } ### 通过源码我们可以看到 `MouseEvent` 继承 `SyntheticEvent`,并且通过 `T` 接收一个 `DOM` 元素的类型, `currentTarget` 的类型由 `EventTarget & T` 组成交叉类型。 ## **事件处理函数类型** ### 当我们定义事件处理函数时有没有更方便定义其函数类型的方式呢?答案是使用 `React` 声明文件所提供的 `EventHandler` 类型别名,通过不同事件的 `EventHandler` 的类型别名来定义事件处理函数的类型。 `EventHandler` 类型实现源码 `node_modules/@types/react/index.d.ts` 。 type EventHandler> = { bivarianceHack(event: E): void }["bivarianceHack"]; type ReactEventHandler = EventHandler<syntheticevent> type ClipboardEventHandler = EventHandler<clipboardevent> type DragEventHandler = EventHandler<dragevent> type FocusEventHandler = EventHandler<focusevent> type FormEventHandler = EventHandler<formevent> type ChangeEventHandler = EventHandler<changeevent> type KeyboardEventHandler = EventHandler<keyboardevent> type MouseEventHandler = EventHandler<mouseevent> type TouchEventHandler = EventHandler<touchevent> type PointerEventHandler = EventHandler<pointerevent> type UIEventHandler = EventHandler<uievent> type WheelEventHandler = EventHandler<wheelevent> type AnimationEventHandler = EventHandler<animationevent> type TransitionEventHandler = EventHandler<transitionevent> `EventHandler` 接收 `E` ,其代表事件处理函数中 `event` 对象的类型。 `bivarianceHack` 为事件处理函数的类型定义,函数接收一个 `event` 对象,并且其类型为接收到的泛型变量 `E` 的类型, 返回值为 `void`。 实例: interface IProps { onClick : MouseEventHandler, } ## **Promise 类型** 在做异步操作时我们经常使用 `async` 函数,函数调用时会 `return` 一个 `Promise` 对象,可以使用 `then` 方法添加回调函数。 `Promise` 是一个泛型类型,`T` 泛型变量用于确定使用 `then` 方法时接收的第一个回调函数(`onfulfilled`)的参数类型。 实例: interface IResponse { message: string, result: T, success: boolean, } async function getResponse (): Promise<iresponse<number[]>> { return { message: '获取成功', result: [1, 2, 3], success: true, } } getResponse() .then(response => { console.log(response.result) }) 我们首先声明 `IResponse` 的泛型接口用于定义 `response` 的类型,通过 T 泛型变量来确定 `result` 的类型。 然后声明了一个 异步函数 `getResponse` 并且将函数返回值的类型定义为 `Promise<iresponse<number[]>>` 。 最后调用 `getResponse` 方法会返回一个 `promise` 类型,通过 then 调用,此时 `then` 方法接收的第一个回调函数的参数 `response` 的类型为,`{ message: string, result: number[], success: boolean}` 。 `Promise` 实现源码 `node_modules/typescript/lib/lib.es5.d.ts`。 interface Promise { /** * Attaches callbacks for the resolution and/or rejection of the Promise. * @param onfulfilled The callback to execute when the Promise is resolved. * @param onrejected The callback to execute when the Promise is rejected. * @returns A Promise for the completion of which ever callback is executed. */ then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise; /** * Attaches a callback for only the rejection of the Promise. * @param onrejected The callback to execute when the Promise is rejected. * @returns A Promise for the completion of the callback. */ catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise; } **** # **工具泛型使用技巧** ### **typeof** 一般我们都是先定义类型,再去赋值使用,但是使用 `typeof` 我们可以把使用顺序倒过来。 const options = { a: 1 } type Options = typeof options ## **使用字符串字面量类型限制值为固定的字符串参数** 限制 `props.color` 的值只可以是字符串 `red`、`blue`、`yellow` 。 interface IProps { color: 'red' | 'blue' | 'yellow', } ## **使用数字字面量类型限制值为固定的数值参数** 限制 `props.index` 的值只可以是数字 `0、 1、 2` 。 interface IProps { index: 0 | 1 | 2, } ## **使用 `Partial` 将所有的 `props` 属性都变为可选值** `Partial` 实现源码 `node_modules/typescript/lib/lib.es5.d.ts` type Partial = { [P in keyof T]?: T[P] }; 上面代码的意思是 `keyof T` 拿到 `T` 所有属性名, 然后 `in` 进行遍历, 将值赋给 `P` , 最后 `T[P]` 取得相应属性的值,中间的 `?` 用来进行设置为可选值。 如果 `props` 所有的属性值都是可选的我们可以借助 `Partial` 这样实现。 import { MouseEvent } from 'react' import * as React from 'react' interface IProps { color: 'red' | 'blue' | 'yellow', onClick (event: MouseEvent): void, } const Button: SFC<partial> = ({onClick, children, color}) => { return (</s></s><div> { children } </div><s> ) ## **使用 `Required` 将所有 `props` 属性都设为必填项** `Required` 实现源码 `node_modules/typescript/lib/lib.es5.d.ts` 。 type Required = { [P in keyof T]-?: T[P] }; 看到这里,小伙伴们可能有些疑惑, `-?` 是做什么的,其实 `-?` 的功能就是把可选属性的 `?` 去掉使该属性变成必选项,对应的还有 `+?` ,作用与 `-?` 相反,是把属性变为可选项。 条件类型 `TypeScript2.8`引入了条件类型,条件类型可以根据其他类型的特性做出类型的判断。 T extends U ? X : Y 原先 interface Id { id: number, /* other fields */ } interface Name { name: string, /* other fields */ } declare function createLabel(id: number): Id; declare function createLabel(name: string): Name; declare function createLabel(name: string | number): Id | Name; ## **使用条件类型** type IdOrName = T extends number ? Id : Name; declare function createLabel(idOrName: T): T extends number ? Id : Name; ## **`Exclude<t,u>`** 从 `T` 中排除那些可以赋值给 `U` 的类型。 `Exclude` 实现源码 `node_modules/typescript/lib/lib.es5.d.ts` 。 type Exclude<t, u=""> = T extends U ? never : T; 实例: type T = Exclude<1|2|3|4|5, 3|4> // T = 1|2|5 此时 `T` 类型的值只可以为 `1 、2 、 5` ,当使用其他值是 `TS` 会进行错误提示。 `Error:(8, 5) TS2322: Type '3' is not assignable to type '1 | 2 | 5'`. ## **`Extract<t,u>`** 从 `T` 中提取那些可以赋值给 `U` 的类型。 `Extract实现源码` `node_modules/typescript/lib/lib.es5.d.ts`。 type Extract<t, u=""> = T extends U ? T : never; 实例: type T = Extract<1|2|3|4|5, 3|4> // T = 3|4 此时`T`类型的值只可以为 `3 、4` ,当使用其他值时 `TS` 会进行错误提示: `Error:(8, 5) TS2322: Type '5' is not assignable to type '3 | 4'`. ## **`Pick<t,k>`** 从 `T` 中取出一系列 `K` 的属性。 `Pick` 实现源码 `node_modules/typescript/lib/lib.es5.d.ts`。 type Pick<t, k="" extends="" keyof="" t=""> = { [P in K]: T[P]; }; 实例: 假如我们现在有一个类型其拥有 `name` 、 `age` 、 `sex` 属性,当我们想生成一个新的类型只支持 `name` 、`age` 时可以像下面这样: interface Person { name: string, age: number, sex: string, } let person: Pick<person, 'name'="" |="" 'age'=""> = { name: '小王', age: 21, } ## **`Record<k,t>`** 将 `K` 中所有的属性的值转化为 `T` 类型。 `Record` 实现源码 `node_modules/typescript/lib/lib.es5.d.ts`。 type Record = { [P in K]: T; }; 实例: 将 `name` 、 `age` 属性全部设为 `string` 类型。 let person: Record<'name' | 'age', string> = { name: '小王', age: '12', } ## **`Omit<t,k>`(没有内置)** 从对象 `T` 中排除 `key` 是 `K` 的属性。 由于 `TS` 中没有内置,所以需要我们使用 `Pick` 和 `Exclude` 进行实现。 type Omit<t, k=""> = Pick<t, exclude<keyof="" t,="" k="">> 实例: 排除 `name` 属性。 interface Person { name: string, age: number, sex: string, } let person: Omit<person, 'name'=""> = { age: 1, sex: '男' } ## **`NonNullable `** 排除 `T` 为 `null` 、`undefined`。 `NonNullable` 实现源码 `node_modules/typescript/lib/lib.es5.d.ts`。 type NonNullable = T extends null | undefined ? never : T; 实例: type T = NonNullable; // string | string[] ## **ReturnType** 获取函数 `T` 返回值的类型。。 `ReturnType` 实现源码 `node_modules/typescript/lib/lib.es5.d.ts`。 type ReturnType any> = T extends (...args: any[]) => infer R ? R : any; `infer R` 相当于声明一个变量,接收传入函数的返回值类型。 实例: type T1 = ReturnType<() => string> // string type T2 = ReturnType<(s: string) => void> // void </s>
Pre:
react-native使用笔记
Next:
MapBox(可自定义, 开源)
0
likes
3
Weibo
Wechat
Tencent Weibo
QQ Zone
RenRen
Submit
Sign in
to leave a comment.
No Leanote account?
Sign up now.
0
comments
More...
Table of content
No Leanote account? Sign up now.