Typescript

191 阅读7分钟

[toc]

1. typescript是什么

  • Typescript是由微软开发的一款开源的编程语言
  • Typescript是Javascript的超集,遵循最新的ES5/ES6规范。TypeScript扩展了Javascript语法
  • TypeScript更像后端Java、C#这样的面向对象语言可以让JS开发大型企业应用
  • 越来越多的项目是基于TS的,比如VSCode、Angular6、Vue3、React16
  • TS提供的类型系统可以帮助我们在写代码的时候提供更丰富的语法提示
  • 在创建前的编译阶段经过类型系统的检查,就可以避免很多线上的错误 image

2. typescript 安装

npm i typescript -g
tsc hello.ts

3. 数据类型

string number boolean 元组 数组 枚举 void null undefined (symbol bigInt) never any(放弃ts检测)

3.1 字符串类型(string)

let str: string = 'cjw'; 

3.2 数字类型 (number)

let num: number = 100;

3.3 布尔类型 (boolean)

let bool: boolean = true;

3.4 元祖

  • 元组 表示长度和类型是固定的数组
let tuple: [string, number, boolean] = ['cjw', 100, true]; // 不能通过索引增加数据
tuple[1] = 200;
tuple.push('abc'); // 元组在通方法 添加数据时只能添加已经存在的类型

3.5 数组类型

let arr2: number[]=[4,5,6];
let arr3: Array<number>=[7,8,9];

3.6 枚举类型

  • 事先考虑某一个变量的所有的可能的值,尽量用自然语言中的单词表示它的每一个值
  • 比如性别、月份、星期、颜色、单位、学历

3.6.1 普通枚举

enum Gender{
    GIRL,
    BOY
}
console.log(`李雷是${Gender.BOY}`);
console.log(`韩梅梅是${Gender.GIRL}`);

enum Week{
    MONDAY=1,
    TUESDAY=2
}
console.log(`今天是星期${Week.MONDAY}`);

3.7 任意类型(any)

  • any就是可以赋值给任意类型
  • 第三方库没有提供类型文件时可以使用any
  • 类型转换遇到困难时
  • 数据结构太复杂难以定义
let root:any=document.getElementById('root');
root.style.color='red';

3.8 null 和 undefined

  • ts中 null 和 undefiend 可以赋值给任何类型(任何类型的子类型) 严格模式中不能将null 和 undefined 赋值给其他类型
  • 严格模式中 null -> null undefined -> undefined
let x: number;
x = 1;
x = undefined;    
x = null;   

let y: number | null | undefined;
y = 1;
y = undefined;   
y = null; 

3.9 void 类型

  • void 表示没有任何类型
  • 当一个函数没有返回值时,TS 会认为它的返回值是 void 类型。
function greeting(name:string):void {
    console.log('hello',name);
}
greeting('cjw');

3.10 never 类型

  1. 程序无法到终点(死循环,抛错)
  2. 判断的时候会出现never
  3. 用never来做一些特殊的处理
function throwError():never{
    throw new Error()
}

function whileTrue():never{
    while (true) {
        
    }
}
function getVal(str:string){ // 在判断永远无法走到的时候 结果是never类型
    if(typeof str == 'string'){
        str
    }else{
        str
    }

}

3.11 类型推论

  • 是指编程语言中能够自动推导出值的类型的能力,它是一些强静态类型语言中出现的特性
  • 定义时未赋值就会推论成any类型
  • 如果定义的时候就赋值就能利用到类型推论

3.12 联合类型

  • 联合类型上只能访问两个类型共有的属性和方法
let name4: string | number;
name4 = 3;
name4 = 'cjw';
console.log(name4.toUpperCase());

3. 13 类型断言

  • 类型断言可以将一个联合类型的变量,指定为一个更加具体的类型
  • 不能将联合类型断言为不存在的类型
let name5: string | number;
(name5 as number).toFixed(3);
(name5 as string).length;
(name5 as boolean);


let ele: HTMLElement | null  = document.getElementById('app');
ele!.style.color = 'red'; // ! 表示非空断言 ,一定不为空。 如果出现为空的清空,自行承担
// es10的语法 链可选运算符 js的语法 用来取值的  下面这两个都是js语法
ele?.style.color // 表示ele有值才取 style属性者undefined,如果是null/ undefined 则返回后面的结果
// 类型断言来处理为空的情况  as 语法
(ele as HTMLElement).style.color = 'red'; // 强制断言成一个类型

3.14 Symbol bigInt

let s1:symbol = Symbol()
let s2 = Symbol() // symbol 是独一无二的 


let big1 = BigInt(Number.MAX_SAFE_INTEGER) + BigInt(1)
let big2 = BigInt(Number.MAX_SAFE_INTEGER) + BigInt(2)
console.log(big1 === big2)

3.15 object

function create(o:object){ // 除了基本类型其他以外的类型可以使用 object
    o
}

create({})
create([]);
create(function(){})

4. 函数

4.1 函数的定义

function hello(name:string):void {
    console.log('hello',name);
}
hello('cjw');

function sum1(a: string, b: string): string{
    return a + b;
}

4.2 函数表达式

type Sum = (c: string, d: string) => string; // 类型别名,类型可以复用
let sum: Sum = function (a: string, b: string) {
    return a + b;
}

4.3 可选参数

function optional(a: string, b?: string, c?:string){

}

4.4 默认参数

function defaultVal(a: string, b: string = '100') { // 可选运算符只能放在最后一个

}

4.5 剩余参数

function spread(...args: number[]) {

}

4.6 函数的重载


function toArray(val:string):string[] // 对条件的限制
function toArray(val:number):number[]
function toArray(val: string | number): string[] | number[] { // 真实的实现
    if (typeof val == 'string') {
        return val.split('');
    } else {
        return val.toString().split('').map(item => Number(item));
    }
}

5 类

5.1 定义类

类中的this 默认不知道它自己具备的什么属性, ts 要做类型检测

class Pointer{
    x:number = 1;
    y:number = 2;  // 如果只添加类型 没有赋值,ts默认不能将null 赋值给其他类型
    constructor(x:number,y?:number){ // 构造函数和普通函数的参数一样可以支持可选参数、 默认参数 、剩余参数
        this.x = x;
        this.y = y!; // 考虑安全性  不能将大范围类型,赋予给小范围类型 (ts的兼容性)
        
        // 真正开发中使用 ! 和 as语法的场景是非常多的
    }
}
let r = new Pointer(100)

5.2 类的修饰符

  • 类的修饰符 java(public、protected、private、readonly) 限制访问的范文
  • public 就意味着公开 自己能访问 儿子能访问 外界能访问
  • protected 自己能访问 儿子能访问 外界不能访问
  • private 自能自己访问
class Animal{
    public readonly type:string = '哺乳类'; // 仅读只能在初始化的时候修改 (只能在构造函数中修改,不能在其他地方修改)
    constructor(type:string){
        this.type = type
    }
    public getType(){
        return this.type
    }
    static flag = '动物'
    static getFlag(){
        console.log(this)
        return this.flag;
    }
    eat(){
        console.log('animal eat');
        return ''
    }
}
class Dog extends Animal{
    constructor(type:string){ // 如果子类写了constrctor 那么子类必须调用super
        super(type); // Animal.call(this);
    }
}
let animal = new Animal('xxx');
let dog = new Dog('xxx');

6. 接口

  • 接口就是抽象的没有具体的实现

  • 接口在开发中会被大量使用 对象(接口可以用来描述对象的形状, 来规定对象中的字段)

  • 接口可以用来描述对象 类 函数 ....

6.1 接口

// type Sum = ((a: string, b: string) => string) |((a: number, b: number) => number) ; // 自定义的类型一般名字都开头大写

interface ISum { // 用于描述函数的接口 , 接口不能被适用于联合类型, 接口的强大之处在于他的继承和实现
    (a: string, b: string): string
}
interface IArgs { // 描述对象的形状
    a: string,
    b: string
}
let sum = ({ a, b }: IArgs) => {
    return a + b
}
// 描述对象

interface IFruit { 
    color:string // 这两个标识必须存在
    taste:string
    size?:number // 标识可有可无
   // [key:string]:any //  其他属性是任意类型 , 名字随便写
}
let fruit1:IFruit = { // 后台返回数据 , 我需要规定后台数据的格式。 
    color:'red',
    taste:'sweet',
    b:1,
} as IFruit
// 如果后台可能不确定size是否存在。

6.2 接口的继承

// 接口可以被其他人来实现 可以是类来实现接口
interface Speakable { // 也可以规定实例中的属性
    speak:()=>void
}
interface SpeakEnglish{
    speakEnglish:()=>void
}

// 类中要满足接口的实现

class Speak implements Speakable, SpeakEnglish{
    // speak!: () => void; // 定义没有具体实现
    // speakEnglish!: () => void;
    speak(){

    }
    speakEnglish(){

    }
}

6.3 函数类型接口

  • 对方法传入的参数和返回值进行约束
interface discount{
  (price:number):number
}
let cost:discount = function(price:number):number{
   return price * .8;
}

6.4 兼容所有的类型

interface IArgs {
    [x:string]: any // key只能是string 或者number
}
let args:IArgs = {
    a:1,
    1:'x',
    [Symbol()]:'1'
}

7.泛型

用来在代码执行时传入的类型,来确定结果

7.1 泛型函数

function createArray<T>(len:number, value:T):T[]{
    let result = [];
    for(let i=0; i<len;i++){
        result.push(value);
    }
    return result;
}

let arr = createArray(3, 'HELLO')
arr[0]
const swap = (tuple:[string,number]):[number,string]=>{
    return [tuple[1], tuple[0]]
}

swap(['2', 33]);

const swap1 = <T, K>(tuple:[T,K]):[K,T]=>{
    return [tuple[1], tuple[0]]
}


swap1<string, number>(['2', 33]);

vue3

1. defineComponent

一层新的包裹,为了提示

2 vue Composition Api

vue3 使用ts实现了类型推断,新版api都采用普通函数 让编写代码时候可以享受完整的类型推断。

<div id="container"></div>

<script src="https://unpkg.com/vue@next"></script>
<script>
    // 获取鼠标位置, 这个功能在很多地方都被复用
    function usePosition(){
        let position = Vue.reactive({x: 0,y:0});
        function update(e){
            position.x = e.pageX;
            position.y = e.pageY;
        }
        Vue.onMounted(() => {
            window.addEventListener('mousemove', update)
        })

        Vue.onUnmounted(() => {
            window.removeEventListener('mousemove', update)
        });
        return Vue.toRefs(position)
    }

    const App = {
        setup(){
            let state = Vue.reactive({ name: 'cjw' });
            let {x, y} = usePosition();
            function change(){
                state.name = 'ddd'
            }
            return {  // 渲染的上下文
                state,
                change,
                x,
                y 
            }
        },
        template: '<div @click="change">{{state.name}} x:{{x}} y:{{y}}</div>'
    }
    Vue.createApp(App).mount('#container')
</script>

3 简单对比 vue2.x 与 vue3.x 响应式

  1. Object.defineProperty只能劫持对象的属性, 而 Proxy 是直接代理对象
  2. Object.defineProperty对新增属性需要手动进行Observe

4 生命周期钩子

image

更多更新

juejin.cn/post/694045…