react - TS

TypeScript

TypeScript 简称『TS』,是微软开发的一个开源的编程语言。

react - TS_第1张图片

一、TS 特点

TS 主要有如下几个特点:

  • 完全兼容 JavaScript,是 JavaScript 的超集

  • 引入类型系统,可以尽早的定位错误位置, 帮助提升开发效率

  let obj = {a:1,b:2....}
  obj = ()=>{}
  console.log(obj.a);
  • 先进的 JavaScript,支持 JavaScript 的最新特性

TypeScript 在社区的流行度越来越高,它非常适用于一些大型项目,

也非常适用于一些基础库,极大地帮助我们提升了开发效率和体验。

二、TS 环境搭建

  • 全局安装:npm i typescript -g或者yarn add global typescript

    • npm root -g : 查看全局包安装的路径
  • 使用命令检查是否安装成功以及查看包的版本:tsc -v

三、TS 初体验

  • typescript 初始化. 创建 ts 的配置文件tsconfig.json 【只要在脚手架里面就需要进行配置文件初始化】
tsc --init 
  1. 创建一个 JS 文件 『hello.ts』

    let str: string = 'hello world';
    console.log(str);
                    //参数类型         //返回值类型
    function add(a: number, b:number):number{
      return a + b;
    }
    console.log(add(1, 100));
    

    注意:ts 本身不能直接运行, 必须要转为 js才可以运行

  2. 命令行运行,这里的后缀是 ts

    tsc hello.ts
    
  3. 命令行运行,这里的后缀是 js

    node hello.js
    

四、Webpack 打包 TS 文件

项目中可以借助 webpack 打包工具来直接处理 ts 文件。操作步骤如下:

  1. 创建目录结构

    - src
        - index.ts
    - public
    	- index.html
    
  2. 安装 webpack 以及相关的工具包

    npm init (-y)
    npm i webpack webpack-cli webpack-dev-server ts-loader html-webpack-plugin typescript  -D
    
  3. 根目录下添加配置文件

    webpack.prod.js

    const HtmlWebpackPlugin = require('html-webpack-plugin')
    
    module.exports = {
        entry: './src/index.ts',
        output: {
            path: resolve(__dirname, '../dist'),
            filename: 'js/bundle.js'
        },
        mode: 'production',
        module: {
            rules: [
                {
                    test: /\.tsx?$/,
                    use: 'ts-loader'
                }
            ]
        },
        plugins: [
            new HtmlWebpackPlugin({
                template: './public/index.html',
                // inject: 'body'
            })
        ],
    
    }
    

    webpack.dev.js

   const configProd = require('./webpack.prod');
   module.exports = {
       ...configProd,
       devServer: {
           host: '127.0.0.1',
           port: 3000,
           open: true
       },
       mode: 'development',
   }
  1. config目录下创建 『tsconfig.json』

    tsc --init
    
  2. 如果想要沿用之前的npm start,需要在package.json配置文件中添加一条配置

   "build": "npx webpack --config ./config/webpack.prod.js",
   "start": "npx webpack serve --config ./config/webpack.dev.js"

五、TS 语法

友情提示:当如果有多个ts文件需要进行导入的话,最终都会变成全局变量来解析,容易发生重名,可以导出{}

5.1 TS 基础类型

TypeScript 支持与 JavaScript 几乎相同的数据类型,此外还提供了实用的枚举类型方便我们使用

TS 支持的变量类型如下:

类型 描述
boolean 限制为布尔类型, true 或者 false
number 限制为任意的数字。 二进制,八进制,十进制,十六进制均可
string 限制为任意的字符串。单引号,双引号,反引号均可
字面量 限制为某个字面量的值
any 限制为任意类型
void 限制为 undefined, 一般用来限制函数的返回值
never 限制函数没有返回值
object 限制为对象类型
array 限制为数组类型
tuple 元组 限制为固定长度与类型的数组
enum 枚举 限制为枚举的数据

5.1.1 布尔类型

最基本的数据类型就是简单的 true/false 值,在JavaScript 和 TypeScript 里叫做 boolean(其它语言中也一样)。

let bool: boolean = true;
console.log(bool); 

let bool1: boolean;
console.log(bool1); //这种写法变量没有赋值,则值就是undefined,但是b变量的数据类型要求是boolean所以报错

let bool2: boolean = true;
bool2 = false;
console.log(bool2)

let bool3: boolean = true;
bool3 = 100; //不能将类型“number”分配给类型“boolean”
console.log(bool3)

const a: boolean = true;
a = false; //无法分配到 "a" ,因为它是常数。
console.log(a)

5.1.2 数字类型

除了支持十进制和十六进制字面量,也支持二进制和八进制字面量。

let num0: number = 0b0110101;//二进制数值
console.log(num0); //53
let num: number = 100; //十进制数值
console.log(num); //100
let num1: number = 0o56; //八进制数值
console.log(num1); //46
let num2: number = 0x5F; //十六进制数值
console.log(num2);//95
let num3: number = Infinity;//无穷大
console.log(num3)//Infinity
let num4: number = 34.56 //浮点数
console.log(num4);//34.56
let num5: number = -56; //负数
console.log(num5); //-56

5.1.3 字符串类型

JavaScript 程序的另一项基本操作是处理网页或服务器端的文本数据。 像其它语言里一样,我们使用 string 表示文本数据类型。 和 JavaScript 一样,可以使用双引号(")或单引号(')表示字符串。

let name:string = 'tom'
name = 'jack'
// name = 12 // error
let age:number = 12
const info = `My name is ${name}, I am ${age} years old!`

5.1.4 字面量类型

TS 允许限制某个变量为固定的某个值,用的很少

let x: 123 = 123;  //变量的值只能是123
// x = 456; //不能修改成其他值,有点类似于const常量
console.log(x)

let y: 'hello';
y = 'hello';
console.log(y)

5.1.5 any

any 类型允许变量的值为任意类型, 并且可以进行任意类型的赋值

let a: any;
a = 100;
a = 'hello';
a = {};
a = [];
console.log(a)

5.1.6 void

void 限制值为 undefined,可以限制变量的值或者是函数的返回值,更多的时候是限制函数的返回值

let v: void;
console.log(v); //undefined


function fn1(): void {
    return;
}
console.log(fn1()); //undefined

let fn = (): void => {
    return;
}
console.log(fn());  //undefined

5.1.7 never

永远不会有值的一种类型(必须存在无法达到的终点),基本不用

function fn(): never {
    throw new Error('出错啦');
}
fn();

5.1.8 对象

object 限制类型为对象,

let obj: object = {name:'张三',age:23};
console.log(obj)

5.1.9 数组

用的比较多

TypeScript 像 JavaScript 一样可以操作数组元素。 不过数组中元素值的类型都是一样的.

有两种方式可以定义数组。

​ 第一种,可以在元素类型后面接上[],表示由此类型元素组成的一个数组:

​ 第二种, 方式是使用数组泛型,Array<元素类型>

//1) 直接咋变量后面添加:类型[] 要求元素中每一个都是限制的这个类型
let arr: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(arr)

let arr1: string[] = ['张三', '李四', '王五'];
//操作数组
arr1.push('赵六');

console.log(arr1)

//2) 泛型  Array<约束类型>
let arr2: Array<Boolean> = [true, false, true];
console.log(arr2)

console.log(arr2.join('/'))

5.1.10 元组

元组(Tuple)类型允许表示一个已知元素数量和类型的数组各元素的类型不必相同用的较少

let persons: [string, number] = ['王二麻子', 18];
console.log(persons)


let arr: [object, Array<number>] = [{ a: 100 }, [10, 20, 30]];
console.log(arr)
console.log(arr[0]);
console.log(arr[1]);

let arr1: [string, number][] = [
    ['张三', 18],
    ['李四', 19],
    ['王五', 20]
]
console.log(arr1)

5.1.11 枚举

枚举(enum)类型是对 JavaScript 标准数据类型的一个补充。

使用枚举类型可以为一组数值赋予友好的名字

一般用于组织一些有相似之处的常量,让这些常量更规范、更统一。

enum gender {
    nan = '男',
    nv = '女',
    screct = '保密'
}

//11.创建一个枚举类型的变量
let sex: object = {
    sex: gender.nv
}
console.log(sex)

5.2 联合类型

联合类型(Union Types)表示取值可以为多种类型中的一种。

let x: string | number;
x = 'hello world'
x = 100;
// x = true; //其他类型不允许
console.log(x);

5.3 类型断言

类型断言(Type Assertion)可以告诉编译器,“相信我,我知道自己在干什么,别报错,出了事我负责”。

let x: string | number;
x = 34.55666;
// console.log(x.toFixed(2));
//方法一:as
// console.log((x as number).toFixed(2))
//方法二:类型
console.log((<number>x).toFixed(2))

5.4 类型推断

TS 会在没有明确的指定类型的时候推测出一个类型。主要有下面两种情况

  1. 变量声明时赋值了,推断为值对应的类型
  2. 变量声明时没有赋值, 推断为 any 类型
let t = 123;
// t = true; //已经赋值了的变量规定为number,再次修改也必须为number
t = 23;
console.log(t)

let y;
y = 100;
y = 'hello';
y = true;
console.log(y)

5.2 函数

TypeScript 为 JavaScript 函数添加了额外的功能

5.2.1 参数与返回值类型

TypeScript 可以为参数与返回值设置类型,代码示例如下:

//1、普通函数
//参数添加类型
function fun(a: number, b: number) {
    console.log(a + b)
}
fun(1, 2);
//添加函数返回值类型
function fun1(x: string, y: number): string {
    return x + y;
}
console.log(fun1('11', 20));

//2、箭头函数
let fun2 = (a: number, b: number): number => {
    return a + b;
}
console.log(fun2(12, 34));

TypeScript 能够根据返回语句自动推断出返回值类型,因此我们通常省略返回值的类型。

5.2.2 函数声明的完整形式

现在我们已经为函数指定了类型,下面让我们写出函数的完整类型。

//4、声明函数
let fun5: (a: number, b: number) => number = (x: number, y: number): number => {
    return x + y;
}
console.log(fun5(10, 20));

5.2.3 可选参数

TypeScript 默认要求函数实参数量要与形参的数量保持一致,不过可以使用『 ?: 』设置参数为可选参数

let fn = (a: number, b: number, c?: number) => {
    console.log(a);
    console.log(b);
    console.log(c);
}

fn(1, 2)

5.2.4 参数默认值

TypeScript 与 JavaScript 一样,允许为参数设置默认值

let fun6: (a: number, b: number, c?: number) => number = (x: number, y: number, z: number = 40): number => {
    return x + y + z;
}
console.log(fun6(10, 20, 100));

5.2.5 剩余参数

针对不定个数参数的函数时,我们可以使用 ES6 提供的 rest 参数来处理。不过在 TypeScript 中需要设置类型。

//剩余参数
function add(a: number, b: number, ...args: number[]){
  //求和
  args = [a, b, ...args];
  return args.reduce((prev: number, current: number) => {
    return prev + current;
  })
}

5.3 类

TS 中的类与 JS 的类使用方式类似, 不过增加了对属性与方法的类型限制

5.3.1 成员类型限制

这里的类型限制跟变量和函数的类型限制是非常相似的

class Student {
    //属性
    name: string = '张三'
    age: number;
    height: number;

    constructor(age: number, height: number) {
        this.age = age;
        this.height = height;
    }

    //方法
    play(): void {
        console.log('玩')
    }

    study(): string {
        return '学习'
    }
}
let s1 = new Student(10, 180);
console.log(s1)

//调用方法
s1.play();
console.log(s1.study())

5.3.2 继承

TypeScript 继承语法与 JavaScript 完全相同

class Person {
    address: string = '北京市'
    name: string;
    age: number;
    height: number;
    constructor(name: string, age: number, height: number) {
        this.name = name;
        this.age = age;
        this.height = height;
    }

    eat(address: string, who: string): string {
        return '吃'
    }
}



class Student extends Person {
    weight: number;
    constructor(name: string, age: number, height: number, weight: number) {
        super(name, age, height);
        this.weight = weight;
    }
    //对父类的方法进行重写
    eat(address: string, who: string): string {
        return this.name + '在' + address + '和' + who + '吃饭';
    }
}

let s1 = new Student('张三', 23, 180, 120);
console.log(s1)

//调用方法
console.log(s1.eat('街边', '女朋友'))

5.3.3 成员修饰符

一些面向对象编程语言(Java, C++)中都有成员修饰符特性,TypeScript 也引入成员修饰符。

成员修饰符有三个:

  • public (默认) 公开的
  • protected 受保护的
  • private 私有的

这些修饰符实现了对象成员的访问控制

自身类 子类 类外部
public
protected X
private X X
//继承
class Father {
  public name: string;
  protected age: number;
  private salary: number;

  constructor(name: string, age: number, salary: number){
    this.name = name;
    this.age = age;
    this.salary = salary;
  }

  info(){
    console.log(this.name);
    console.log(this.age);
    console.log(this.salary);
  }
}

class Son extends Father{
  constructor(name: string, age: number, salary: number){
    super(name, age, salary);
  }

  checkSalary(){
    console.log(this.name);
    console.log(this.age);
  }
}

let xue = new Son('xue', 26, 16000);

console.log(xue.name);

5.4 接口

5.4.1 基本使用

TypeScript 中引入了接口,用来限制对象的结构与类型。代码示例:

//声明接口
interface BoyFriend{
    name: string;
    age: number;
}
//声明对象 满足接口结构与类型要求
let zhangsan: BoyFriend = {
    name: '张三',
    age: 18,
}

console.log(zhangsan);

上述代码中,对象的属性不能多, 也不能少,属性值的类型也必须满足接口的要求

5.4.2 可选属性

如果某些属性不是固定的,只是某些条件下存在,可以使用可选属性配置

interface BoyFriend{
    name: string,
    age: number,
    car ?: string
}

这样设置之后,对象中的 car 属性就不是必须的属性

5.4.3 只读属性

如果一些属性的值不允许修改,则可以使用『readonly』标志,这样一旦发现被修改,立即报错

interface BoyFriend{
    readonly id: number,
    name: string,
    age: number,
    car ?: string
}

这样设置后, 如果修改 id 属性, 编译器就会报错

readonly 与 const 的功能很像,不过 readonly 是限制对象的属性, const 是限制变量的值

5.4.4 限制方法

接口除了可以限制属性类型之外,也可以对对象的方法进行限制

interface BoyFriend{
    readonly id: number,
    name: string,
    age: number,
    car ?: string,
    //必选
    cook: () => void,
    //可选
 	skeep?: () => void  
}
 //当如果接口中的定义的方法为可选的方法的时候,在对象实现的时候并且调用那么程序将认为这个可选的方法属性有可能存在,也有可能不存在
//如果存在则是接口中的定义的方法值,如果不存在则为undefiend
//解决办法有两个
//1、修改tsconfig.json文件中的strict严格模式为false,如果修改了配置文件需要[重启脚手架],那么将不在进行严格的检查  但是这种形式会忽略到一些其他的语法检查 [不太推荐]
//2、只要调用可选方法,在调用的()的前面添加一个!,程序就会认为该方法skeep一定是存在 [推荐]
console.log(obj.speek!()) */
    
    obj.skeep!()

该接口要求对象必须要有 cook 方法且返回结果必须为 undefined

5.4.5 类与接口

之前接口只能限制单个对象的结构与类型,接口与类结合之后,可以约束一类对象的结构与类型

interface BoyFriend {
    name: string;
    age: number;
    car ?: string;
    cook: () => void
}

class Person implements BoyFriend{
    name: string;
    age: number;
    car: string;

    constructor(name: string, age: number, car: string){
        this.name = name;
        this.age = age;
        this.car = car;
    }

    cook(){
        console.log('我可以做蛋炒饭~~');
    }
}

5.4.6 类的多实现

一个类可以同时实现多个接口,类必须要包含对应的属性和方法才能通过编译

语法:class 类名 implements 接口名称1,接口名称2…{}

interface BoyFriend{
    readonly id: number,
    name: string,
    age: number,
    car ?: string,
    cook: () => void  
}

interface Staff{
    name: string
    age: number
    programTS: () => void;
}

class Person implements BoyFriend, Staff{
    //对象属性
    id:number
    name: string
    age: number

    //构造方法
    constructor(id: number, name: string, age: number){
        this.id = id;
        this.name = name;
        this.age = age;
    }

    //对象的方法
    cook(): void{
        console.log('做方便面。。。');
    }

    //对象方法
    programTS(){
        console.log('我可以编写 TypeScript');
    }
}

5.4.7 接口的继承

当接口中出现重复结构时,可以对公共部分进行抽离,然后通过继承来简化代码

interface BasicInfo{
    name: string,
    age: number,
}

interface BoyFriend extends BasicInfo{
    readonly id: number,
    car ?: string,
    cook: () => void  
}

interface Staff extends BasicInfo{
    programTS: () => void;
}

5.5 泛型

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

5.5.1 引入

下面创建一个函数, 实现功能: 根据指定的数量 count 和数据 value , 创建一个包含 countvalue 的数组 不用泛型的话,这个函数可能是下面这样:

function createArray (count:number,value:any):any[]{
  const arr:any[] = []
  for (let index = 0; index < count; index++) {
    arr.push(value)
  }
  return arr
}

const arr01 = createArray(3,'hello')
const arr02 = createArray(3,100)

console.log(arr01[0].split('')) //运行不报错,但编码时没有提示
console.log(arr02[0].toFixed(3)) //运行不报错,但编码时没有提示
console.log(arr02[0].split('')) //运行报错,但编码时没有提示错误 

5.5.2 泛型函数

function createArray <P>(count:number,value:P):P[]{
  const arr:P[]= []
  for (let index = 0; index < count; index++) {
    arr.push(value)
  }
  return arr
}

const arr03 = createArray<string>(3,'hello')
const arr04 = createArray<number>(3,100)
console.log(arr03[0].split(''))
console.log(arr04[0].toFixed(1))
console.log(arr04[0].split('')) //error 类型“number”上不存在属性“split”

5.5.3 多个泛型参数的函数

一个函数可以定义多个泛型参数

function createArray <T,P> (a: T, b: P): [T, P] {
  return [a, b]
}

const result = createArray<string, number>('abc', 123)
console.log(result[0].length)
console.log(result[1].toFixed())

5.5.4 泛型接口

在定义接口时, 为接口中的属性或方法定义泛型类型
在使用接口时, 再指定具体的泛型类型

// 声明一个接口
interface Response<T>{
  status: number,
  headers: object,
  data: T,
}

interface Stu{
  id: number,
  name: string,
  age: number,
}

interface Book{
  id: number,
  title: string,
  price: number
}

//一个对象
let response: Response<Book> = {
  status: 200,
  headers: {},
  data: {
    id: 1,
    title: '西游记',
    price: 28
  }
}

let response2: Response<Stu> = {
  status: 200,
  headers: {},
  data: {
    id: 1,
    name: 'xx',
    age: 19
  }
}

5.5.5 泛型类

在定义类时, 为类中的属性或方法定义泛型类型 在创建类的实例时, 再指定特定的泛型类型

//泛型类
class Container<T>{
  //用于储存数据
  store: T[];
  constructor(store: T[]){
    this.store = store;
  }
}

let books = new Container<Book>([{id: 1, title: '西游记', price: 10}, {id: 2, title: '三国演义', price: 25}])

5.5.6 泛型约束

如果我们直接对一个泛型参数取 length 属性, 会报错, 因为这个泛型根本就不知道它有这个属性

// 没有泛型约束
function fn <T>(x: T): void {
  // console.log(x.length)  // error
}

我们可以使用泛型约束来实现

interface Lengthwise {
  length: number;
}

// 指定泛型约束
function fn2 <T extends Lengthwise>(x: T): void {
  console.log(x.length)
}

fn2('abc')
// fn2(123) // error  number没有length属性

5.6 其他

5.6.1 类型声明

可以使用 type 关键字声明类型

//1. 类型声明
type Computer = {
  brand: string,
  price: number
}

interface Person{
  name: string,
  age: number
}

type Persons = Person[];

//2. 获取某个变量的类型
let me: string = '尚硅谷';
type SchoolType = typeof me;

//3. 获取接口键名的联合类型
function getInfo(obj: Person, key: keyof Person): void{
  obj[key]
}

//4. 获取函数的返回值类型
type retType = ReturnType<typeof getInfo>;
                          
//5. 获取函数参数类型. 返回类型为『元组』类型
type paramsType = Parameters<typeof getInfo>

5.6.2 内置类型

JavaScript 中有很多内置对象,它们可以直接在 TypeScript 中当做定义好了的类型。

内置对象是指根据标准在全局作用域(Global)上存在的对象。

这里的标准是指 ECMAScript 和其他环境(比如 DOM)的标准。

5.6.2.1 ECMAScript 的内置对象
  1. Boolean
  2. Number
  3. String
  4. Date
  5. RegExp
  6. Error
let b: Boolean = new Boolean(1)
let n: Number = new Number(true)
let s: String = new String('abc')
let d: Date = new Date()
let r: RegExp = /^1/
let e: Error = new Error('error message')
b = true
// let bb: boolean = new Boolean(2)  // error

5.6.2.2 BOM 和 DOM 的内置对象

  • Window
  • Document
  • HTMLElement
  • DocumentFragment
  • Event
  • NodeList
const div: HTMLElement = document.getElementById('test')
const divs: NodeList = document.querySelectorAll('div')
document.addEventListener('click', (event: MouseEvent) => {
  console.dir(event.target)
})

六、typescript 的脚手架

6.1 创建 TS 版本的 react 应用

# 创建项目
create-react-app react-ts --template typescript

# 进入目录
cd react-ts

# 启动服务
npm start

6.2 React V18

import ReactDOM from 'react-dom/client'
import App from './App'

// 创建应用根对象, 指定页面容器元素
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)

// 渲染App组件
root.render(<App />)

6.3 React 严格模式

文档: https://zh-hans.reactjs.org/docs/strict-mode.html

在 React 严格模式下, 一些不好的语法使用会在浏览器控制台显示相应的错误提示

只在开发模式下起作用, 生产环境打包时会自动去除

开启 React 严格模式

<React.StrictMode>
	<App/>
</React.StrictMode>

建议在开发阶段, 关闭这个严格模式, 该模式会导致每次输出内容, 弹出两次, 影响调试

你可能感兴趣的:(React,react.js,前端,前端框架)