linuxg下c++ 类导出_TypeScript踩坑集锦(下)

tsconfig.json 常用配置项注释

export class Triangle { /* ... */ }export class Square { /* ... */ }

tsconfig.json 配置项问题

1. 三种 JSX 模式

  • 在 TS 中想要使用 JSX 必须做两件事:
  1. 给文件一个 .tsx 扩展名
  2. 启用 jsx 选项
  • TS 具有三种 JSX 模式:preserve,react 和 react-native,这些模式只在代码生成阶段起作用,类型检查并不受影响。
  • preserve 模式下: 不会将 JSX 编译成 JS,生成代码中会保留 JSX,以供后续的转换操作使用(比如:Babel)。 另外,输出文件会带有 .jsx 扩展名。
  • react 模式下: 直接将 JSX 编译成 JS,会生成 React.createElement 的形式,在使用前不需要再进行转换操作了,输出文件的扩展名为 .js。
  • react-native 模式下: 相当于 preserve,它也保留了所有的 JSX,但是输出文件的扩展名是 .js。

模式输入输出输出文件扩展名preserve

2. "lib" 配置项需要注意的问题

  • 当你安装 TypeScript 时,会顺带安装 lib.d.ts 等声明文件,此文件包含了 JavaScript 运行时以及 DOM 中存在各种常见的环境声明
  • 它自动包含在 TypeScript 项目的编译上下文中
  • 它能让你快速开始书写经过类型检查的 JavaScript 代码
  • tsconfig.json 中的 lib 选项用来指定当前项目需要注入哪些声明库文件。如果没有指定,默认注入的库文件列表为:
  • 当 --target ES5:DOM,ES5,ScriptHost
  • 当 --target ES6:DOM,ES6,DOM.Iterable,ScriptHost
  • 如果在 TS 中想要使用一些 ES6 以上版本或者特殊的语法,就需要引入相关的类库。如:ES7 、DOM.Iterable

3. "moduleResolution" 解析策略

https://www.tslang.cn/docs/handbook/module-resolution.html

4. 指定 target 为 es6 时,tsc 就会默认使用 "classic" 模块解析策略,这个策略对于 `import * as abc from "@babel/types"` 这种非相对路径的导入,不能正确解析。

  • 解决方法:指定解析策略为 node => "moduleResolution": "node"。

5. "esModuleInterop" 具体作用是什么

  • 如果一个模块遵循 ES6 模块规范,当默认导出内容时(export default xxx),ES6 模块系统会自动给当前模块的顶层对象加上一个 default 属性,指向导出的内容。当一个 ES6 模块引入该模块时(import moduleName from 'xxx'),ES6 模块系统默认会自动去该模块中的顶层对象上查找 default 属性并将值赋值给 moduleName。而如果一个非 ES6 规范的模块引入 ES6 模块直接使用时(var moduleName = require('xxx')),就会报错,需要通过 moduleName.default 来使用。
  • TypeScript 为了兼容,引入了 esModuleInterop 选项,设置 esModuleInterop 为 true ,在编译时自动给该模块添加 default 属性,就可以通过 import moduleName from 'xxx' 的形式导入 非 ES6 模块,不再需要使用 import moduleName = require('xxx') 的形式。

6. "allowSyntheticDefaultImports" 具体作用是什么

  • 允许 默认导入 没有设置默认导出(export default xxx)的模块,可以以 import xxx from 'xxx' 的形式来引入模块
const enum Colors {    Red,    Yellow,    Blue}// 常量枚举会在编译阶段被删除let myColors = [Colors.Red, Colors.Yellow, Colors.Blue];

7. "paths" 配置路径映射集合时,需要注意的问题

{   "paths": {      // 这里的路径后面必须跟着 "/*"      "@public/*": [        // 这里的路径后面必须跟着 "/*"        "public/*"      ],      "@src/*": [        "src/*"      ],      "@assets/*":[        "src/assets/*"      ],      "@components/*": [        "src/components/*"      ]    }}

8. "allowJs" 时需要注意的问题

  • 设置 "allowJs": false :在 .ts / .tsx 文件中引入 .js / .jsx 文件时,就不会有相关提示
1c9bfe44fb80f2fb2086015d25b2ca85.png

image.png

React + TS 项目问题

1. 使用 import 引入非 JS 模块会报错,而使用 require 则没有问题

interface Test {    arr: string[]}// pick 摘取返回的结果 => {arr: string[]}let aaa: Pick = {arr: ['1']};
dc384573eb305a3210748a6dc4d639cc.png

image.png

解决办法: 给这些非 JS 模块添加声明

/** * style */declare module '*.css'declare module '*.less'// declare module "*.less" {//     const styles: { [className: string]: string };//     export default styles// }declare module '*.scss'/** * 图片 */declare module '*.svg'declare module '*.png'declare module '*.jpg'declare module '*.jpeg'declare module '*.gif'declare module '*.bmp'

2. import * as React from 'react' 和 import React from 'react' 有什么区别

  • 第一种写法是将所有用 export 导出的成员赋值给 React ,导入后用 React.xxx 访问
  • 第二种写法仅是将默认导出(export default)的内容赋值给 React

3. 解决 import * as xxx from 'xxx' 这种奇怪的引入方式

  • 配置 tsconfig.json
// 数字索引——约束数组// index 是随便取的名字,可以任意取名// 只要 index 的类型是 number,那么值的类型必须是 stringinterface StringArray {  // key 的类型为 number ,一般都代表是数组  // 限制 value 的类型为 string  [index:number]:string}let arr:StringArray = ['aaa','bbb'];console.log(arr);// 字符串索引——约束对象// 只要 index 的类型是 string,那么值的类型必须是 stringinterface StringObject {  // key 的类型为 string ,一般都代表是对象  // 限制 value 的类型为 string  [index:string]:string}let obj:StringObject = {name:'ccc'};
interface Counter {    (start: number): string;    interval: number;    reset(): void;}function getCounter(): Counter {    let counter = function (start: number) { };    counter.interval = 123;    counter.reset = function () { };    return counter;}let c = getCounter();c(10);c.reset();c.interval = 5.0;

4. 对 antd 组件库进行按需加载

  • 这里使用的是 ts-loader 转译 TS 方案,更多方案请看 Webpack 转译 Typescript 现有方案

.babelrc

// 注意区别// 普通的接口interface discount1{  getNum : (price:number) => number}// 函数类型接口interface discount2{  // 注意:  // “:” 前面的是函数的签名,用来约束函数的参数  // ":" 后面的用来约束函数的返回值  (price:number):number}let cost:discount2 = function(price:number):number{   return price * .8;}// 也可以使用类型别名type Add = (x: number, y: number) => numberlet add: Add = (a: number, b: number) => a + b

tsconfig.json

{  "compilerOptions": {    "target": "es5",    "jsx": "preserve",// 保留 jsx     ...}

webpack.config.js

{  test: /.tsx?$/,    use: [      'babel-loader',      'ts-loader'    ]},

5. 声明通过 React.createRef()创建的 ref 类型

class Father {    str: string; // 默认就是 public    public name: string;   // 在定义的类中、类的实例、子类、子类实例都可以访问    protected age: number; // 只能在定义的类和子类中访问,不允许通过实例(定义的类的实例和子类实例)访问    private money: number; // 只能在定义的类中访问,类的实例、子类、子类实例都不可以访问    constructor(name: string, age: number, money: number) {        this.name = name;        this.age = age;        this.money = money;    }    getName(): string {        return this.name;    }    setName(name: string): void {        this.name = name;    }}const fa = new Father('aaa', 18, 1000);console.log(fa.name);// aaaconsole.log(fa.age);// errorconsole.log(fa.money);// errorclass Child extends Father {    constructor(name: string, age: number, money: number) {        super(name, age, money);    }    desc() {        console.log(`${this.name} ${this.age} ${this.money}`);    }}let child = new Child('bbb', 18, 1000);console.log(child.name);// bbbconsole.log(child.age);// errorconsole.log(child.money);// error

6. react + redux + react-redux 项目:使用 @connect 装饰器正常,但是一旦结合 TS 后,就会报错

https://segmentfault.com/a/1190000016047027

import {ComponentClass} from 'react'import {    connect as nativeConnect,    MapDispatchToPropsParam,    MapStateToPropsParam} from 'react-redux'import {withRouter as nativeWithRouter} from 'react-router-dom'export type ComponentDecorator

 = >(WrappedComponent: T) => Texport const connect: 

(    mapState: MapStateToPropsParam, P, S>, // mapDispatch?: MapDispatchToPropsParam, P>    mapDispatch?: any) => ComponentDecorator = nativeConnect as any;export const withRouter: ComponentDecorator = nativeWithRouter as any;

7. react + redux + react-redux 项目:在使用 mapStateToProps(state) 函数时,想要给仓库中的 state 声明类型

  • 借助 ReturnType
function attr(val: string): string;function attr(val: number): number;// 前面两行是函数申明,这一行是实现函数重载function attr(val: any): any {    if (typeof val === 'string') {        return val;    } else if (typeof val === 'number') {        return val;    } }attr('aaa');attr(666);
// setScene 模块import * as types from '../types/action-types';import {appEditAction} from '../actions/common';export interface SetSceneState {    loadSuccess: boolean;    loadProgress: number;}let initState: SetSceneState = {    loadSuccess: false,    loadProgress: 0,};export default function (state: SetSceneState = initState, action: appEditAction) {    switch (action.type) {        case types.SCENE_DATA_LOADSUCCESS: {            return {...state, loadSuccess: action.payload.success};        }        case types.SCENE_DATA_LOADINGPROGRESS: {            return {...state, loadProgress: action.payload.num};        }        default:            return state;    }}

使用

d6241968a4055978d37d128c39ac70c3.png

image.png

8. react + redux + react-redux 项目:想要给 action creator 函数声明类型

// 在 Mesh 组件中import workActions from "@store/actions/work";interface MeshProps {    // 刚开始我是这样写的,每次都得在组件的 Props 里重新声明一下函数    // updateSceneData?: (workId: string,data) => appEditAction;    updateData?: typeof workActions.updateData;}@connect(null, {    updateData: workActions.updateData,})class Mesh extends React.Component {...}
// store/actions/work.tsimport * as types from '../types/action-types';import {appEditAction} from "@edit-store/actions/common";export default {    updateWorkData(workId: string, data: any): appEditAction {        return {type: types.UPDATE_WORK_ASYNC, payload: {workId, data}}    }}

9. react + redux + react-redux 项目:给 React 组件的 Props 声明类型(较为便捷的方法)

import * as React from 'react';import {RouteComponentProps} from 'react-router';import {connect} from "@store/connect";import {AppState} from "@store/reducers";import commonActions from "@store/actions/commonActions";// 组件可能有四个属性来源// 1.mapStateToProps 的返回值// 2.actions 对象类型// 3.来自路由// 4.父组件传进来的其它属性// 原先的写法:一个个拼起来,mapStateToProps 返回的状态还得在 Props 接口里再声明一遍,比较混乱、麻烦// interface Props {//     loadProgress?: number;//     markVisible?: boolean;//     setMarkVisible?: typeof commonActions.setMarkVisible;// }function mapStateToProps(state: AppState) {    const {markVisible,loadProgress} = state;    return {        markVisible,        loadProgress,    };}// 现在的写法:便捷type StateProps = ReturnType;type DispatchProps = typeof commonActions;interface IParams {}type RouteProps = RouteComponentProps;type Props = StateProps & RouteProps & DispatchProps & {};@connect(mapStateToProps, {    setMarkVisible: commonActions.setMarkVisible})export default class App extends React.PureComponent {    render() {        const {markVisible, loadProgress} = this.props;        return (
 {markVisible} {loadProgress} 
);    }}

10. react + redux + react-redux 项目:想要给 redux-thunk 声明类型

redux thunk 有一个内置类型 ThunkAction,我们可以这样使用:

// src/thunks.tsimport { Action } from 'redux'import { sendMessage } from './store/chat/actions'import { AppState } from './store'import { ThunkAction } from 'redux-thunk'export const thunkSendMessage = (  message: string): ThunkAction> => async dispatch => {  const asyncResp = await exampleAPI()  dispatch(    sendMessage({      message,      user: asyncResp,      timestamp: new Date().getTime()    })  )}function exampleAPI() {  return Promise.resolve('Async')}

11. 使用 webpack 的 module.hot 会警告没有类型定义

# 下载这个类型声明文件$ npm install --save @types/webpack-env
if (process.env.NODE_ENV !== 'production') {    if (module.hot) {        module.hot.accept('./reducers', () => store.replaceReducer(rootReducer));    }}

12. tsconfig-paths-webpack-plugin 这个包会将 tsconfig.json 中的 path 配置项内容映射到 webpack 配置中去,这样就不需要在 webpack 中的 alias 配置项里配置路径映射

61ea28d610dec480139d77a6caebccdf.png

image.png

13. react 函数组件声明

interface Greeting {    name: string;    age: number;}const Hello:React.FC = (props) => 

Hello {props.name}

;// 推荐使用第二种const Hello2 = (props:Greeting) => 

Hello {props.name}

;

14. 如何编写 react + ts 版的 HOC

import React, { Component } from 'react';import HelloClass from './HelloClass';interface Loading {    loading: boolean}// HOC 可以接收一个类组件,也可以接收一个函数组件,所以参数的类型是 React.ComponentType// 源码:type ComponentType

 = ComponentClass

 | FunctionComponent

;function HelloHOC

(WrappedComponent: React.ComponentType

) {    return class extends Component

 {        render() {            const { loading, ...props } = this.props;            return loading ? 

Loading...
 : ;        }    }}export default HelloHOC(HelloClass);

15. 快速获取事件处理函数的 event 参数类型

 class Login extends React.Component {    handlerLinkBtnClick = (ev) => {          console.log(ev);        this.props.historyGo('./register');    };    handlerLinkBtnMouseMove = (ev) => {       console.log(ev);    };    render() {        return (            
                                    

This is Login Page 

                    
                         Go to Register Page                   
                            
        );    }}

按住 Ctrl ,然后鼠标移动到事件名上就能获取当前事件处理函数的参数类型

65b4ead5d02c72f31cc370e1ad9da403.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值