美文网首页
2021-01-28

2021-01-28

作者: 不二要多吃饭长胖 | 来源:发表于2021-01-29 15:08 被阅读0次


    一:ts初步了解

    基础类型

    ts的基础类型中有如下几种:boolean / number / string / object / 数组 / 元组 / 枚举 / any /undefined / null / void / never

    布尔类型:boolean  取值只有true / false

    const IS_MOBILE:boolean = true;

    const IS_SUPER_ADMIN:boolean = false;


    数字类型:number 整数/小数都包括, 同时支持2/8/10/16进制字面量.

    let decLiteral: number = 6; // 十进制

    let hexLiteral: number = 0xf00d; // 十六进制

    let binaryLiteral: number = 0b1010; // 二进制

    let octalLiteral: number = 0o744; // 八进制


    字符串类型:string

    let s1:string = 'hello world!';

    let s2:string = 'hello ${name}`;


    数组类型:Array

    数组有2种表示方式:

    第1种, 在指定类型后面增加[], 表示该数组内的元素都是这个指定类型:

    let numbers:number[] = [1,2,3,4,5];

    // number|string代表联合类型, 下面的高级类型中会讲

    let numbers:(number|string)[] = [1,2,3,4,'5'];

    第2种, 通过泛型表示, Array<元素类型>, 后面需要去深入了解泛型, 这里先做初步了解即可:

    let numbers:Array<number> = [1,2,3,4,5];


    元组(Tuple)

    元组类型表示一个已知元素数量和类型的数组, 各元素的类型不必相同:

    let list1:[number, string] = [1, '2', 3]; // 错误, 数量不对, 元组中只声明有2个元素

    let list2:[number, string] = [1, 2]; // 错误, 第二个元素类型不对, 应该是字符串'2'

    let list3:[number, string] = ['1', 2]; // 错误, 2个元素的类型颠倒了

    let list4:[number, string] = [1, '2']; // 正确


    枚举(enum)

    枚举是ts中有而js中没有的类型, 编译后会被转化成对象, 默认元素的值从1开始, 如下面的Color.Red的值为1, 以此类推Color.Green为2, Color.Blue为3:

    enum Color {Red, Green, Blue}

    // 等价

    enum Color {Red=1, Green=2, Blue=3}

    当然也可以自己手动赋值:

    enum Color {Red=1, Green=2, Blue=4}

    并且我们可以反向通过值得到他的键值:

    enum Color {Red=1, Green=2, Blue=4}

    Color[2] === 'Green' // true


    any(任意类型):顶级类型

    any代表任意类型, 也就是说, 如果你不清楚变量是什么类型, 就可以用any进行标记, 比如引入一些比较老的js库, 没有声明类型, 使用的时候就可以标记为any类型, 这样ts就不会提示错误了. 当然不能所有的地方都用any, 那样ts就没有使用的意义了.

    let obj:any = {};

    // ts自己推导不出forEach中给obj增加了'a'和'b'字段.

    ['a', 'b'].forEach(letter=>{

        obj[letter] = letter;

    });

    // 但是因为标记了any, 所以ts认为a可能存在

    obj.a = 123


    void类型

    void的意义和any相反, 表示不是任何类型, 一般出现在函数中, 用来标记函数没有返回值:

    function abc(n:number):void{

        console.log(n);

    }

    void类型对应2个值, 一个是undefined,一个null:

    const n1:void = undefined;

    const n2:void = null;

    null 和 undefined

    默认情况下null和undefined是所有类型的子类型, 比如:

    const n1:null = 123;

    const n2:undefined = '123';

    注意: 这是因为默认情况下的编译选项strictNullChecks为false, 但是为了避免一些奇怪的问题出现, 我还是建议大家设置为true(编译选项设置的内容), 请用精准的类型去标注.(官方文档默认为false)

    如果一个变量的值确实需要是null或者undefined, 可以像下面这么用, ts会自动根据if/else推导出正确类型:

    // 这是"联合类型", 在"高级类型"中会有详细介绍, 表示n可能是undefined也可能是number

    let num: undefined|number;

    if(Math.random()>0.5) num = 1;

    if(undefined !== num) {

        num++;

    }


    never类型

    never类型 表示不可达, 官网也没有具体描述, 基本上主要使用在throw的情况下:

    function error():never{

        throw '错了!';

    }


    object

    object 表示非原始类型, 也就是除numberstringbooleansymbolnullundefined之外的类型:

    let o1:object = [];

    let o2:object = {a:1,b:2};


    高级类型入门

    通过基础类型组合而来的, 我们可以叫他高级类型. 包含: 交叉类型 / 联合类型 /  类型推论 / 接口 等等

    接口(interface)

    一种定义复杂类型的格式 例如:

    interface Article {

        title: stirng;

        count: number;

        content:string;

        fromSite: string;

    }

    const article: Article = {

        title: '为vue3学点typescript(2), 类型',

        count: 9999,

        content: 'xxx...',

        fromSite: 'baidu.com'

    }

    在这种情况下,当我们给article赋值的时候, 如果任何一个字段没有被赋值或者字段对应的数据类型不对, ts都会提示错误, 这样就保证了我们写代码不会出现上述的小错误.

    非必填(?) &&readonly

    还是上面的例子, lang的意思是文章的语言,如果文章都是中文, 该字段就不会有值, 但是如果我们不传又会提示错误, 怎么办? 这时候就需要标记lang字段为非必填, 用"?"标记:

    interface Article {

        title: stirng;

        count: number;

        content:string;

        lang?: string; // 非必填

        readonly gender:string; // 性别只读

    }

    // 不会报错

    const article: Article = {

        title: '为vue3学点typescript(2), 类型',

        count: 9999,

        content: 'xxx...',

    }

    用接口定义函数

    接口不仅可以定义对象, 还可以定义函数:

    // 声明接口

    interface Core {

        (n:number, s:string):[number,string]

    }

    // 声明函数遵循接口定义

    const core:Core = (a,b)=>{

        return [a,b];

    }

    用接口定义类

    先简单看下如何给类定义接口

    // 定义

    interface Animate {

        head:number;

        body:number;

        foot:number;

        eat(food:string):void;

        say(word:string):string;

    }

    // implements

    class Dog implements Animate{

        head=1;

        body=1;

        foot=1;

        eat(food){

            console.log(food);

        }

        say(word){

            return word;

        }

    }


    交叉类型(&)

    交叉类型是将多个类型合并为一个类型, 表示"并且"的关系,用&连接多个类型, 常用于对象合并:

    interface A {a:number};

    interface B {b:string};

    const a:A = {a:1};

    const b:B = {b:'1'};

    const ab:A&B = {...a,...b};


    联合类型(|)

    交叉类型也是将多个类型合并为一个类型, 表示""的关系,用|连接多个类型:

    function setWidth(el: HTMLElement, width: string | number) {

        el.style.width = 'number' === typeof width ? `${width}px` : width;

    }


    类型推论

    以下代码虽然没有指定类型,但是会在编译的时候报错:

    let myFavoriteNumber='seven';

    myFavoriteNumber=7;// index.ts(2,1): error TS2322: Type 'number' is not assignable to type 'string'.

    事实上,它等价于:

    let myFavoriteNumber:string='seven';

    myFavoriteNumber=7;// index.ts(2,1): error TS2322: Type 'number' is not assignable to type 'string'.

    TypeScript 会在没有明确的指定类型的时候推测出一个类型,这就是类型推论。

    如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成 any 类型而完全不被类型检查:

    let myFavoriteNumber;

    myFavoriteNumber='seven';

    myFavoriteNumber=7;  // yes


    二: 泛型进阶

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

    首先,我们来实现一个函数 createArray,它可以创建一个指定长度的数组,同时将每一项都填充一个默认值:

    上例中,我们使用了之前提到过的数组泛型来定义返回值的类型。

    这段代码编译不会报错,但是一个显而易见的缺陷是,它并没有准确的定义返回值的类型:

    Array<any> 允许数组的每一项都为任意类型。但是我们预期的是,数组中每一项都应该是输入的 value 的类型。

    这时候,泛型就派上用场了:

    上例中,我们在函数名后添加了 <T>,其中 T 用来指代任意输入的类型,在后面的输入 value: T 和输出 Array<T> 中即可使用了。

    接着在调用的时候,可以指定它具体的类型为 string。当然,也可以不手动指定,而让类型推论自动推算出来:

    泛型约束:在函数内部使用泛型变量的时候,由于事先不知道它是哪种类型,所以不能随意的操作它的属性或方法:

    上例中,泛型 T 不一定包含属性 length,所以编译的时候报错了。

    这时,我们可以对泛型进行约束,只允许这个函数传入那些包含 length 属性的变量。这就是泛型约束:

    上例中,我们使用了 extends 约束了泛型 T 必须符合接口 Lengthwise 的形状,也就是必须包含 length 属性。

    此时如果调用 loggingIdentity 的时候,传入的 arg 不包含 length,那么在编译阶段就会报错了:

    泛型接口

    可以先使用接口的方式来定义一个函数需要符合的形状:

    当然也可以使用含有泛型的接口来定义函数的形状:

    进一步,我们可以把泛型参数提前到接口名上:

    泛型类参数的默认类型

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

    三:vue+ts项目实践基础

    一:构建

    1:npm install -g vue/cli

        2:vue create typescript-vue-demo

        3:选择了TypeScript 和 Babel 选项 如下图

    参考:https://github.com/SimonZhangITer/vue-typescript-dpapp-demo

               https://ts.xcatliu.com/advanced/generics.html

    相关文章

      网友评论

          本文标题:2021-01-28

          本文链接:https://www.haomeiwen.com/subject/pmsftltx.html