读懂TypeScript

数据类型

一、定义变量

TS 中创建变量有四个要素:

  1. 定义变量的关键字:varletconst
  2. 变量名
  3. 变量的数据类型
  4. 变量的初始值

语法结构如下:

let 变量名: 数据类型 = 初始值

注意,变量的初始值必须是当前定义的数据类型。

例如:

let a:number = 10;

二、TS 的数据类型

1、基础类型

  • 数字 number:TS 中不管是整数还是小数都属于 number 类型;
  • 字符串 string:单引号、双引号、ES6 的模板字符串都属于 string 类型;
  • 布尔值 boolean:true 和 false;
let a: number = 10;
let b: string = 'hello';
let c: boolean = true;

2、null 和 undefined

TS 中的 null 和 undefined,跟 JS 中的一样,null 类型下的数据只有 null 本身,undefined 类型下的数据也只有它自身。

let d: null = null;
let e: undefined = undefined;

在 TS 中,这两个数据类型本身的作用不是很大。

3、any 类型

any 表示任意数据类型,意味着我们可以将任何变量都设置成 any 类型。

let f: any = 1;
let g: any = 'hello';

但是,尽量不要使用该类型。

4、void

void 从概念来说,刚好和 any 相反,它表示没有任何类型。

通常,当一个函数没有返回值得时候,我们会将返回值的类型设置为 void

基础语法:

function 函数名(): 返回值类型 {

}

示例代码:

function foo(): void {

}

5、数组

TS 中要求数组中所有元素的数据类型必须一致,因为我们在通过 TS 定义数组时,必须先声明数组中子元素的数据类型。

基础语法:

let 变量名: 子项类型[] = 数组值;

示例代码:

//语法一:
let user1:number[] = [1,2,3]

let user2:string[] = ['xiaowang','xiaoliu']

//语法二:
let cover1:Array<string> = ['xiaowang','xiaoliu']

6、元组

元组类型,允许创建一个已知数组子项的数量和类型的数组,数组中子项的类型可以不一样。

基础语法:

let 变量名: [类型一, 类型二] = [值一, 值二];

示例代码:

let i: [number, string, boolean] = [1, 'a', true];

7、对象

基础语法:

let 变量名: { 属性名一: 数据类型, 属性名二: 数据类型 } = { 属性名一: 值, 属性名二: 值 }

示例代码:

let j: { name: string, age: number } = { name: '张三', age: 20 }

8、枚举

我们在实际开发中,很多时候会使用数字来表示一些状态。例如:

  • 在设置性别时,会用数字 1 表示男性,用数字 0 表示女性;
  • 在设置订单状态时,会用数字 0 表示订单支付失败,数字 1 表示订单支付成功,数字 2 表示订单超时…

大部分时候,我们没办法记住每一个数字所对应的含义,因此,TS 中提供了枚举的类型来描述每一个数字的含义。

基础语法:

enum 自定义名字 {
    含义 = 数字一,
    含义 = 数字二,   
}

示例代码:

enum gender {
    female = 1,
    male = 0
}
const student = { name: '张三', age: 20, gender: gender.female }
console.log(student); // { name: '张三', age: 20, gender: 1 }

9、never

never 类型表示永远不存在的值的类型。

例如某一个函数中抛出了异常,对于该函数的返回值来说,就永远都不存在,因此该函数的返回值的类型可以设置为 never

示例代码:

function foo(): never {
    throw new Error('错误')
}

10、unknow

unknow 是 TS 3.0 中新增的类型。它和 any 类似,任意类型的数据都可以设置为 unknow

示例代码:

let k: unknown = 1;
let l: unknown = 'hello';

unknowany 的区别在于:

任何类型的值都可以赋值给 any,同时,any 类型的值也可以赋值给任何类型。

let m:any = 1;
m = true;
let n: string = m;

任何类型的值都可以赋值给 unknow,但是,unknow 类型的值只能赋值给 unknowany

let o: unknown = "a";
let p: any = o;
// let q: string = o; // 报错

函数

一、基础语法

JS 中创建函数分为两种方式:函数声明、函数表达式。

1、函数声明

在 JS 中函数声明的语法如下:

function 函数名(形参名) {
    return 返回值;
}

在 TS 中函数声明的语法如下:

function 函数名(形参名: 数据类型): 返回值类型 {
    return 返回值;
}

2、函数表达式

在 JS 中函数表达式的语法如下:

const 变量名 = function(形参名) {
    return 返回值
}

在 TS 中函数表达式的语法涉及到变量的赋值,因此,TS 中函数表达式的语法分为以下几种情况:

1)只约束参数和返回值的类型
const 变量名 = function(形参名: 数据类型): 返回值类型 {
    return 返回值
}
2)只约束变量的类型
const 变量名: (形参名: 数据类型) => 返回值类型 = function(形参名) {
    return 返回值
}
3)约束参数、返回值以及变量的类型
const 变量名: (形参名: 数据类型) => 返回值类型 = function(形参名: 数据类型): 返回值类型 {
    return 返回值
}

通常,约束了变量 的类型,就不需要再去函数中约束参数和返回值的类型了。形式一和形式二任选其一即可。

二、函数参数

1、基本类型的参数

function foo(name: string, age: number) {
    console.log(name, age);
}
foo('张三', 20)

2、参数为数组

function foo(arr: number[]) {
    console.log(arr);
}
foo([1, 2, 3])

3、参数为对象

function foo(student: { name: string, age: number }) {
    console.log(student);
}

foo({ name: '张三', age: 20 })

4、参数的默认值

function foo(name: string, age: number = 20) {

}
foo('李四')

注意:通常将带默认值的参数放在所有形参的最后。

5、可选参数

可选参数,指的就是当前参数可以传也可以不传:

function foo(name: string, age?: number) {

}
foo('李四')

注意:通常将带可选参数放在所有形参的最后。

6、不定参数(剩余参数)

形参中在参数名的前面加上 ...,该参数就变成了不定参数。不定参数的值永远都是一个数组。

function foo(a: number, ...b: number[]) {

}
foo(1, 2, 3)

注意:不定参数必须放在所有形参的最后。

三、函数的返回值

1、基本类型的返回值

function foo(): string {
    return 'hello'
}

2、返回数组

function foo(): number[] {
    return [1, 2, 3]
}

3、返回对象

function foo(): { x: number, y: number } {
    return { x: 1, y: 2 }
}

4、没有返回值

function foo(): void {

}

四、箭头函数

const add = (x: number, y: number): number => x + y;
const add: (x: number, y: number) => number = (x, y) => x + y;

类型断言

有些时候我们会遇到一种情况,我们开发者比 TS 更清楚某一个数据的信息。

例如某一条数据 TS 检测出来该数据的类型可能会有问题,但是我们作为开发者,我们确定当前数据的类型,然后我们就可以通过断言的方式,告诉 TS:相信我,我知道自己在干什么。

一、基础语法

类型断言有两种语法:<>as。基础语法格式如下:

<数据类型>变量名

变量名 as 数据类型

除了语法不同外,<>as 没有任何区别,但是因为在 React 中 <> 语法会与 JSX 语法出现冲突,所以更推荐使用 as

二、示例代码

示例代码一:

let b = (<string>a).length;
let b = (a as string).length;

示例代码二:

const arr: number[] = [1, 2, 3, 4];
const result: number = arr.find(item => item > 3) as number;

联合类型与类型别名

一、联合类型

联合类型,指的就是我们可以将多个数据类型通过 | 联合成一个整体。类似于 JS 中 || 运算符的作用。

基础语法:

变量名: 类型一 | 类型二 | 类型三

变量的值只要满足联合类型中的其中一个类型即可。

代码案例

示例代码:

let a: string | number = 20;
a = 'hello';

在实际开发中,联合类型通常会搭配 undefined 使用:

function foo(a: number | undefined) {

}
foo(1);

二、类型别名

类型别名,指的是可以通过 type 来给某一个类型取一个新名字(但不会创建一个新的类型),常用于联合类型。

基础语法:

type 别名 = 类型;

通常建议别名的首字母大写。

代码案例

案例代码一:

type Params = string | number;

let a: Params = 20;
let b: Params = 'hello';

案例代码二:

type Foo = (x: number, y: number) => number;
const foo: Foo = (x, y) => x + y;

接口和对象

在 TS 中,关于对象属性的类型约束,会比较繁琐,例如:

const student: { name: string, age: number,  gender: string } = { name: '张三', age: 20, gender: '男' };
const teacher: { name: string, age: number,  gender: string } = { name: '李四', age: 30, gender: '女' }

在 TS 中,提供了接口(interface)来定义对象的类型约束。

一、基础语法

interface 接口名 {
    属性名一: 数据类型;
    属性名二: 数据类型;
    // ...
}

建议接口名首字母大写。

代码示例:

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

const student: Person = { name: '张三', age: 20, gender: '男' };
const teacher: Person = { name: '李四', age: 30, gender: '女' };

二、接口的可选属性

在属性名后添加 ? 来将当前属性设置为可选属性:

interface Person {
    name: string;
    age: number;
    gender?: string;  // 可选属性
}

const student: Person = { name: '张三', age: 20, gender: '男' };
const teacher: Person = { name: '李四', age: 30 };

三、只读属性

在属性名前面添加 readonly 来将属性设置为只读属性,即可以访问,但是不能修改。

interface Person {
    readonly name: string;
    age: number;
    gender?: string;  // 可选属性
}

const student: Person = { name: '张三', age: 20, gender: '男' };
const teacher: Person = { name: '李四', age: 30 };
// student.name = "王五"; // 报错

四、任意属性

任意属性是指,在接口中设置一个任意属性,那么在使用该接口时,就可以匹配一个任意名称的属性了。

interface Person {
    readonly name: string;
    age: number;
    gender?: string;  // 可选属性
    [propName: string]: any  // 任意属性
}

const student: Person = { name: '张三', age: 20, gender: '男', likes: ['吃饭', '睡觉'] };
const teacher: Person = { name: '李四', age: 30, tel: '13112312311' };

注意:在一个接口中如果定义了任意属性,那么其他属性的类型,必须是任意属性类型的子集。

type PropType = string | number | string[] | undefined;

interface Person {
    readonly name: string;
    age: number;
    gender?: string;  // 可选属性
    [propName: string]: PropType  // 任意属性
}

const student: Person = { name: '张三', age: 20, gender: '男', likes: ['吃饭', '睡觉'] };
const teacher: Person = { name: '李四', age: 30, tel: '13112312311' };

接口和函数

一、约束函数参数类型

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

function foo(student: Person) {

}

foo({ name: '张三', age: 20 })

二、约束函数返回值类型

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

function foo(student: Person): Person {
    return student;
}

foo({ name: '张三', age: 20 })

三、约束函数的类型

基础语法:

interface 接口名 {
    (参数名: 数据类型): 返回值类型
}

示例代码:

interface Foo {
    (student: Person): Person
}

const foo: Foo = (student) => {
    return student;
}

foo({ name: '张三', age: 20 })

四、接口中使用接口

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

interface Foo {
    (student: Person): Person
}

const foo: Foo = (student) => {
    return student;
}

foo({ name: '张三', age: 20 })

五、type 和 interface 的区别

type,是对已存在的类型取一个新的名字,并不会创建一个新的类型出来,常用于联合类型。

interface ,常用于定义对象的类型约束,通过 interface 定义的类型,等同于是创建了一个新的类型结构。

class类

一、基础语法

class 类名 {

}

二、类的属性

基础语法:

class 类名 {
    属性名: 数据类型 = 属性值;
    contructor(形参名: 数据类型) {
        this.属性名 = 属性值;
    }
}

代码示例:

interface State {
    name: string;
    age: number
}

class Person {
    state: State = {
        name: '张三',
        age: 20
    }
}

三、类的方法

基础语法:

class 类名 {
    方法名(形参名: 数据类型): 返回值类型 {
        return 返回值
    }
    方法名 = (形参名: 数据类型): 返回值类型 => {
        return 返回值
    }
}

四、访问修饰符

修饰符 含义 作用范围
public(默认) 公共类型 当前类、子类、外部
protected 受保护类型 当前类、子类
private 私有类型 当前类
readonly 只读类型(不能修改) 当前类、子类、外部

示例代码:

class Person {
    public name: string = "张三"
    sayName() {
        console.log(this.name)
    }
}

class Student extends Person {
    introduce(age: number): void {
        console.log(this.name)
    }
}

const s = new Student();
console.log(s.name);

泛型

一、函数中的泛型

基础语法:

function 函数名<类型变量名>(参数名: 类型变量名): 类型变量名 {
    return 返回值;
}
函数名<数据类型>(参数)

当函数调用时,<数据类型> 中的数据类型会传递到函数的“类型变量名”身上。

示例代码:

function foo<T>(x: T): T {
    return x;
}
foo<number>(100);
foo<string>('100');

定义多个泛型变量

function foo<T, U>(x: T, y: U): U {
    return y;
}
foo<number, string>(100, 'hello');

二、接口中的泛型

基础语法:

interface 接口名<类型变量名> {
    属性名: 类型变量名
}

const 变量名: 接口名<数据类型> = 值;

示例代码:

interface Person<T> {
    name: string;
    age: T
}

const student: Person<number> = { name: '张三', age: 20 }
const teacher: Person<string> = { name: '张三', age: '20' }

三、class 中的泛型

基础语法:

class 类名<类型变量名> {
    属性名: 类型变量名;
    contructor(形参名: 类型变量名) {
        this.属性名 = 形参名;
    }
}

new 类名<数据类型>(实参)

示例代码:

class Person<T> {
    age: T;
    constructor(age: T) {
        this.age = age;
    }
}

new Person<number>(20);
new Person<string>('20');
posted @ 2022-03-29 23:07  lian_chao  阅读(116)  评论(0)    收藏  举报