React项目重构到TS+React版本

储备知识

基本数据类型

布尔 数字javascript

元祖css

const author:[string, string] = ['mx', '大风']
复制代码

枚举, 好比应用于订单状态html

enum Order {
  finish = '订单完成',
  deleted = '订单删除',
  send = '订单已发出'
}
复制代码

any 放弃类型检查html5

  • ? 无关紧要
function users(name?:string) {
  console.log(name)
}
function users(age:number = 18, name?:string) {
  console.log(name)
}
function users(...numbers: number[]) {
  console.log(name)
}
复制代码

class

public private protectedjava

public name: string;  //类里面 子类 其它任何地方外边均可以访问
    protected age: number; //类里面 子类 均可以访问,其它任何地方不能访问
    private money: number; //类里面能够访问, 子类和其它任何地方都不能够访问
复制代码

声明文件

安装 TypeScript 时,会顺带安装 lib.d.ts 声明文件。此文件包含了 JavaScript 运行时以及 DOM 中存在各类常见的环境声明node

对于项目中一些全局可用的变量或者接口,能够考虑建立一个globals.d.tsreact

globals.d.ts 能够看作是 lib.d.ts 的扩充webpack

接口

TypeScript的核心原则之一是对值所具备的结构进行类型检查git

基本使用

在TypeScript里,接口的做用就是为这些类型命名和为你的代码或第三方代码定义契约。es6

定义属性

interface props {
  readonly name: string
  habit? : string
}
复制代码

函数 && 接口

定义一个函数所需的形状

  • 函数声明
interface fnBox {
  (len:number, cont: number): number[]    
}
let pushAry:fnBox
pushAry = function (len: number, cont: number) {
  return new Array(len).fill(cont)    
}
复制代码

若是这里故意写错cont的类型,会有什么提示

inetrface

能够定义无返回值的函数

interface props {
  once(): void 
  twice: () => void 
}
复制代码
  • 函数表达式

咱们也可使用函数表达式去书写函数

let sing = () => {-- do something --}
复制代码

函数表达式添加约束能够写为

let sing = (singer: string): boolean => {-- do something --}
复制代码

可是这种只是对等号右侧的匿名函数进行了类型定义,而等号左边的 sing,是经过赋值操做进行类型推论而推断出来的

手动给 sing 添加类型,则应该是这样:

let sing: (singer: string) => boolean = (singer: string): boolean => { -- do something-- }
复制代码

类 && 接口

implements 可使类 具备接口的属性功能

interface int2 {
  once(): void,
  touchMore: (count: number) => void
}

class Btn implements int2 {
  once () {
    console.log('once')
  }
  touchMore (count: number) {
    console.log('touchMore')
  }
}

const btns = new Btn
btns.once()
btns.touchMore(9)
复制代码

class

配置 tsconfig.json

1 使用webpack搭建项目的时候,有配置alias参数

'utils': path.resolve(__dirname, '../utils')
复制代码

这样在组件中引入的时候,文件路径能够简化

import { log } from 'utils/statistics'
复制代码

不过在使用ts以后,会发现组件中有警告信息,表示找不到此模块

就须要另外在tsconfig中添加配置参数

"baseUrl": "./",
    "paths": {
      "components": ["./components/*"],
      "utils": ["./utils/*"],
    }
复制代码

2 other

noEmitOnError: true
复制代码

当编译出错,则不输出编译后的文件

全局变量 window

在访问页面的时候,server会反馈一些基本的用户信息,好比用户名,设备版本号等,将这些所有挂载在CONFIG变量中了

<script type="text/javascript">
  window.CONFIG = JSON.parse(decodeURIComponent('{{feConfig}}'))
</script>
const {uid, version} = window.CONFIG // 而后在组件中能够直接获取
复制代码

可是在加入TS以后,会提示window中不存在属性CONFIG

window

TS不容许获取,设置没有声明过的属性,因此这里报错了

处理方案

1 全局扩展

在模块内部添加声明到全局做用域

在入口文件index.tsx中 添加声明

declare global {
   interface Window { CONFIG: any }
 }
 const {uid} = window.CONFIG
复制代码

2 使用类型断言

const { apk } = (window as any).CONFIG
复制代码

3 添加 globals.d.ts 声明文件

interface Window {
  CONFIG: any
}
复制代码

泛型

import * as React from 'react'

class App extends React.Component<props, state>{
    -- do something --
}
复制代码

定义

泛型是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性

好比写一个根据指定内容填充到指定长度的数组生成函数 getAry

function getAry (len: number, cont: string | number): string[] | number[] {
  return new Array(len).fill(cont)
}
复制代码

参数

参数 含义 类型
len 指定长度 number
cont 指定内容 string 或 number (使用联合类型处理)

因为不肯定参数cont的输入类型,因此返回值使用了联合类型处理

这种须要 返回值类型和输入参数类型保持一致的状况,可使用泛型T来处理

泛型是类型变量,一种用来表示类型的特殊变量

  • 使用方式

在函数名后添加<>

function createFn<T>
function createFn<string> // 明确指定 T 是 string 类型的
复制代码

其实泛型函数的类型与非泛型函数的类型没什么不一样,只是多了一个类型参数在最前面

  • 能够指定默认类型

TypeScript 2.3 之后,咱们能够为泛型中的类型参数指定默认类型。当使用泛型时没有在代码中直接指定类型参数,从实际值参数中也没法推测出时,这个默认类型就会起做用

function beConfusion<T = boolean> (name: string, isDone: boolean) {...}
复制代码

泛型接口

将上面那个函数使用接口来定义

interface dealFn {
  <T>(len: number, cont: T): T[]    
}
let getAry: dealFn
getAry = function <T> (len: number, cont: T): T[] {
 --do something--    
}
复制代码

泛型类

泛型类使用<>括起泛型类型,跟在类名后面

class DealAry<T> {
  value: T
  constructor (value: T) {
    this.value = value
  }
  deal () {
    console.log(this.value)
  }
}
复制代码

other

  • 其他的一些泛型变量

虽然能够本身定义泛型变量结构,可是通常会使用已定义好的泛型

Promise

async taobaoGoods =  function (ids: number[]): Promise<string> {
  return new Promise <string>((reslove, reject) => {
    try{
      reslove('success')
    } catch {
      reject('failture')
    } 
  }) 
}
复制代码
  • 能够有多个泛型变量
class 复制代码

React.component 类的泛型变量

打开 node_modules/@types/react 能够看到 component 类

component

简单归纳就是

class Component<P = {} , S = {} > {
  -- other --
  readonly props: Readonly<{ children?: ReactNode }> & Readonly<P>
  state: Readonly<S>
  -- other --
}
复制代码

能够看到 props 和 state 两个对象都是只读的

因此咱们在写React组件的时候,要调整为

interface BannerProps {
  showUpdate(): void,
  clickOnce: (type: string, id: number) => void
}

interface BannerState {
  once: boolean
}

export default class Banner extends React.Component<BannerProps, BannerState> {
  --do something--
} 

复制代码

类型断言

获取一个元素的某个属性

componentDidMount () {
  const target = this.refs.img
  if (target.getAttribute('src') != newSrc) { -- do something-- }   
}
复制代码

ts提示有错误

HTMLElement

这是由于TS推断target 还不具有getAttribute 属性

TypeScript 容许你覆盖它的推断,而且能以你任何你想要的方式分析它,这种机制,被称为「类型断言」

TypeScript 类型断言用来告诉编译器你比它更了解这个类型,而且它不该该再发出错误

<类型>值 或者 值 as 类型
复制代码

*** 在jsx中必须使用 第二种方式去处理 ***

在不肯定类型的时候就访问其中一个类型的属性或方法,可使用类型断言

function getType (arg: string | boolean): boolean {
  if ( arg.length ) return true
  return false
}
复制代码

这种其实会报错的,若是输入是布尔值,则没有length

加入类型断言

function getType (arg: string | boolean): boolean {
  if ( (arg as string).length  ) return true
  // if ( (<string>arg).length ) return true
  return false
}
复制代码

断言成一个联合类型中不存在的类型是不容许的

if ( (arg as array).length  ) return true // 报错
复制代码

因此上面组件里 须要调整为

const target = this.refs.img as HTMLElement 
复制代码

内置对象

JavaScript 中有不少内置对象,能够直接在 TypeScript 中当作定义好了的类型

const isEnd:Boolean = new Boolean(false)

interface createEle {
  createElement(tagName: "div"): HTMLDivElement    
}

复制代码

设置组件属性

interface videoProps {
    poster?: string
}

class Video extends Component<videoProps> {
    static defaultProps = {
        poster: ''
    }
}
复制代码

webpack 调整为 ts 格式

新项目中将webpack部分调整为ts处理

参考文章,官网地址

储备知识

ts-node 能够直接运行.ts文件 ts版本使用方式见官网

tsconfig

tsconfig.webpack.json中的配置直接按照官网中去写的

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es5",
    "esModuleInterop": true
  }
}
复制代码

tsconfig

这里配置的是es5 将其调整为es6便可

或者使用 webpack-merge 进行模块合并

const config: Configuration = merge(commonPlugin, {...})

复制代码

未解决的问题

  • 关于 import 模块

项目中保留了一份 webpack.common.js的文件,发如今 import 模块的时候 会先找到 这个.js的 而不是 .ts

import commonPlugin from './webpack.common'
复制代码

ts.config 中有一个 allowJs 参数 若是设置为TRUE 则能够引入js文件 可是这个默认的是FALSE 因此应该不会有引入 js文件

因此很奇怪 - 文档

暂时将js文件名修改了

掉坑记录

::写法

<Banner once={::this.update} />
复制代码

这个主要是借助了bable 的 transform-function-bind 双冒号实现绑定

TS不支持这种写法 能够调整为

<Banner once={() => this.update} />
<Channel clickOnce={this.clickOnce.bind(this)} /> 复制代码

issue

es6的新语法

组件中有使用

const result = Object.assign({}, params, info)
复制代码

处理方案

1 借助lodash

安装lodash.assign和@types/lodash

2 更换复制对象方案

3 调整tsconfig配置文件

以前

target: es5
复制代码

调整为

target: es6
复制代码

注意可能须要重启 VScode 才能够生效

3 img 元素属性

在获取img元素的src属性的时候,是这么写的

(target as HTMLElement).getAttribute('src')
复制代码

而后在直接设置src值的时候

(item as HTMLElement).src = itemSrc
复制代码

这样就会报错,须要调整为

(item as HTMLImageElement).src = itemSrc
复制代码

getAttribute 属于 HTMLElement 属性,而 src 属于 HTMLImageElement 的属性

补充一下 element HTMLElement node 的属性方法

element对象

htmlelement对象

node对象

后续还在调整中,继续更新掉坑记录部分

相关文章
相关标签/搜索