读懂TypeScript
数据类型
一、定义变量
TS 中创建变量有四个要素:
- 定义变量的关键字:
var、let、const - 变量名
- 变量的数据类型
- 变量的初始值
语法结构如下:
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';
unknow 和 any 的区别在于:
任何类型的值都可以赋值给 any,同时,any 类型的值也可以赋值给任何类型。
let m:any = 1;
m = true;
let n: string = m;
任何类型的值都可以赋值给 unknow,但是,unknow 类型的值只能赋值给 unknow 或 any。
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');

浙公网安备 33010602011771号