欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

TypeScript笔记(1)

程序员文章站 2022-03-05 09:13:05
...

类型

基本类型

TypeScript与JavaScript的区别就是TypeScript更加严谨,这里的严谨体现在对每一个变量的类型要求上,定义这个变量是,就要定义这个变量的类型,而在JavaScript中,变量主要有5个原始数据类型。

布尔值,数值,字符串,null,undefined。(正经来说,对象也是一个原始数据类型,但是在ts中,对象和前几个规则差的很多,所以等下再说,还有Symbol,在日常中我并不怎么使用这个东西,所以按下不表)

let Boo: boolean = false;

Boo是变量名,在变量名后面跟冒号,冒号后面是数据类型。

其中boolean是布尔值的意思,同理字符串值使用的string,数值使用的是number,null和undefined使用的都是分别是null和undefined。

这里要多说一句,null和undefined是所有类型的子类型,既number类型的值可以是null或者undefined。

let u: undefined;
let num: number = u;

//这样是合法值

与JavaScript不同的是,在TypeScript中,还有空值的概念,既当一个函数不返回任意一个值的时候,他返回的是空值,在这里空值用void声明。

function test(): void{
    console.log('test')
}

当有返回值的时候,我们就需要给返回值设定一个类型

let num: number = 55 
function renum(num): number{
    console.log(num);
    return num
}

特殊类型

在所有的类型之外,还有一个类型的叫任意值类型。这种类型的变量可以被赋予任意类型的值。

let num: any = 55;
num = 'five'

这样是合法的。并且可以调用所有类型的所有方法,ts并不做检查,虽然最后执行可能还是报错,但是在ts这里是合法的,例

let num: any = 55;
console.log(num.sayhi())

这样的代码是可以通过ts的检查的,但是他实际是无法运行的,因为num只是一个变量,没有sayhi方法。

当不注明具体类型的时候,变量会被ts识别为any类型。

这里有两种情况,一个是在声明的时候直接赋予值,另一种是先声明,然后赋予值,例

let num = 'five';
num = 5;

//这样会报错

let num;
num = 'five';
num = 5;

//这样不会报错

为什么呢?因为ts还有一套类型推论,如果再声明的时候是

let num = 'five';

是等价于

let num: string = 'five';

let num;

则等价于

let num: any;

故而前者是字符串类型,后者是任意类型。

那么如果变量可能有两个类型,我们是不是就必须用any类型了呢?ts还提供了一种联合类型供我们使用。

let numstring: number | string;
numstring = 55;
numstring = 'five'

但是这里要注意,当我们调用该变量的属性的时候,只能调用这两个变量的共有属性,而不能调用他们各自独有的,既

function test(a: number | string): number{
    return a.length
}

是不合法的,因为number类型并没有length属性。如果想要合法,就要删掉a的number类型。

function test(a: string): number{
    return a.length
}

这样就是合法的了。

对象类型

刚刚我们说了对象类型和其他类型不太一样,那么哪里不一样呢?对象类型需要引入一个接口的概念。这里的接口不是用于和后端交互的,而是一个对象的属性规则,用于前端的交互。

interface Person {
    name: string;
    age: number;
}

这样就做了一个人接口,在使用的时候,我们就需要按照人接口给出的规则创建个体人。

let tom: Person = {
    name: 'Tom',
    age: 25
};

其实可以把人这个接口看做前面的类型,既Person在这里和number是类似的。不同的是,接口字母需要大写,这个不是强制要求。

在上面那个Person的规定下,人必须有两个属性,不能多也不能少,这样就很局限了,所以TypeScript还提供了可选属性与任意属性。

先说可选属性,可选属性就是在冒号前面添加一个问号,ts就会认为这个属性是可选属性。

interface Person {
    name: string;
    age?: number;
};

let tom: Person = {
    name: 'Tom'
};

再说任意属性,这里有一个问题,那就是可选属性其实就是任意属性,当我们任意属性的键名为可选属性的键名时,他就等同于可选属性。所以任意属性是比可选属性等级更高的,则可选属性的类型必须是任意属性的子类型,既

interface Person {
    name: string;
    age?: number;
    [propName: string]: string;
}

let tom: Person = {
    name: 'Tom',
    age: 25,
    gender: 'male'
};

对于这段代码来说,因为可选属性age的类型是number,而任意属性的类型是string,所以当我们创建一个名为age属性的时候,ts并不会去找可选属性,而是首先查看任意属性的类型,因为任意属性的类型是string,所以ts无法编译这边代码。

所以可选属性的类型必须是任意属性类型的子属性。

说完了初始化属性,我们还要考虑权限问题,有一些属性我们是不希望更改的,也就是只读属性,

interface Person {
    readonly id: number;
    name: string;
    age?: number;
    [propName: string]: any;
}

let tom: Person = {
    id: 89757,
    name: 'Tom',
    gender: 'male'
};

tom.id = 9527;

这个就没什么好解释的了,很简单的东西,看一下就好了。

数组类型

数组类型通过类型+方括号来表示

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

其中num是数组名,number是数组类型,所以在名为num的数组中是不允许有number类型以外的东西存在的。

函数类型

函数也很简单,因为函数是有输入,有输出的,所以我们不仅要限定输入,也要对输出限制

function sum(x: number, y: number): number {
    return x + y;
}

如果函数没有返回值,那么函数的返回值类型为void。

函数还有另一种写法

let mySum: (x: number, y: number) => number = function (x: number, y: number): number {
    return x + y;
};

这里的箭头函数(=>)不是es6的箭头函数,而是TypeScript的函数定义,随着es7,es8的完善,TypeScript可能会跟进这些改变,所以我个人不太喜欢这种写法,容易搞混。

函数还可以用之前说到的接口来定义

interface Sum {
    (source: number, subString: number): number;
}

let sum: Sum;
sum = function(add, otheradd) {
    return add + otheradd;
}

这里肯定有人要问了,如果我在函数自变量处强行规定另一种类型会怎么样呢?

例如

interface Sum {
    (source: number, subString: number): number;
}

let sum: Sum;
sum = function(add: string, otheradd) {
    return add + otheradd;
}

console.log(sum('456',555))

这样编译会报错,这里的规则只看接口,因为已经规定好了这个函数的出和入的变量类型,所以后续再更改是无效的。这条规则也是ts的基础规则,既一旦设定类型,就不能再更改。

上面这些都是设定的很死的规则,对象类型都有可选属性,难道作为一等公民的函数会没有嘛,当然不,下面说一下可选参数

function connection (one: string, otherone?: string) {
    return one + '' + otherone;
}

这样第二个参数就是一个选填的参数。

这里要注意一点,那就是选填的参数不能在必填参数前面,否则ts没办法判断到底是必填参数还是选填参数。

既然有了可选参数,那么在es6中的参数默认值也是有的,用法和es6也一致。

function connection (one: string = 'one', otherone?: string) {
    return one + '' + otherone;
}

和js中有剩余参数的说法,既

function sum(add, ...items) {
    let sum = add;
    items.forEach(function(item) {
        add = add + item
    });
    return add;
}
let a = sum(0,1,2,3,4)
// a = 10

在TypeScript中,基本沿用了es6中的规定,不同的是,TypeScript多了一个类型的规定

function sum(add: number, ...items: number[]) {
    let sum = add;
    items.forEach(function(item) {
        add = add + item
    });
    return add;
}
let a = sum(0,1,2,3,4)
// a = 10

这里要强调的一点是,items是一个数组,而不是单独的某个数,所以这里对items的类型定义是成分数值类型的数组。

写到这里有经验的前端程序员就应该已经看出来TypeScript的优势了,数值可以相加,数值和字符串也可以相加,但是这时候就并不是我们想要的结果了,而TypeScript可以很好的解决这个问题。

断言类型

前面说到复合类型在使用类型的属性的时候,只能使用共有属性,而不能使用特有的,但是有的时候我们就是要使用这些类型怎么办呢?这里就要用到断言类型了。

断言类型是手动的指定,假如这个值是这个类型,他不是改变一个值的类型。

function getLength(something: string | number): number {
    if ((<string>something).length) {
        return (<string>something).length;
    } else {
        return something.toString().length;
    }
}

这里的就是断言类型,他假设something这个值是string类型的情况下,执行的东西。

内部对象

JavaScript有很多内部对象大家都是知道的,TypeScript对JavaScript的内部对象的使用也添加了一层规定,让这样的使用变得更加的规范

Math.pow(10, '2');

在JavaScript中,这样的语句是不标准的,但是合法可运行的,但是在TypeScript中,这样是无法通过编译的,要用标准的写法

Math.pow(10, 2);
相关标签: TypeScript