TypeScript
TypeScript
团队编码时事先约定好数据的类型,那么后续编写并调用这些设置好类型的变量时就会强制起约束作用
原始数据类型
| number | string | boolean | null | undefined | void | symbol | bigint|
正确的书写方式
function App() {
const tutureSlogan: string = "图雀社区,汇聚精彩的免费实战教程";
return <div className="App">{tutureSlogan}</div>;
}
错误的书写方式
function App() {
const tutureSlogan: string = 123;
return <div className="App">{tutureSlogan}</div>;
}
//Type '123' is not assignable to type 'string'. TS2322
解析:
给原 JS 的 tutureSlogan 变量加上了类型定义,它是一个 string 类型的变量,通过这样的操作,原 JS 变量的类型就被静态化了,在初始化时,就不能再赋值其他的类型给这个 tutureSlogan 变量了,比如我们将 number 类型的字面量赋值给 tutureSlogan ,就会报错~~~~
非原始数据类型
- array
- tuple
- enum
tuple
和 enum
则是 TS 中新增的类型,JS 中正式提案中目前是没有的
const arr: string[] = ["1", "2", "3"];
特殊类型
any 类型定义
any
的字面含义是 “任何”,主要用于在编码的时候不知道一个变量的类型,所以先给它加一个 any
类型定义,表示它可以是任何类型,一般留待后续确认此变量类型之后再将 any
改为具体的类型
let test: any;
不要一碰到不确定的就写个 any
类型,然后写了之后还不改,那就把 TS 用成了 AnyScript 了,这就和 JS 一样了 😉。所以你看呀,TS 的优秀之处在于,你完全可以在 TS 的环境中写 JS 还能享受 TS 带来的各种静态语言的优势
unknown 类型定义
unknown
类型和 any
都可以表示任何类型,应用场景也和上面类型,但是它更安全
let testOne: any;
let testTwo: unknow;
不清楚具体类型又打算继续开发时,上面两种情况都可以使用,但是当我们具体使用这两个变量的时候,any
类型的变量是可以进行任意进行赋值、实例化、函数执行等操作,但是 unknown
只允许赋值,不允许实例化、函数执行等操作
联合类型
联合类型(Union Types)表示取值可以为多种类型中的一种
联合类型使用 | 分隔每个类型
let test: any | number = "哇哈哈";
test = 123;
类型推论
TypeScript 会在没有明确的指定类型的时候推测出一个类型,这就是类型推论
如果没有明确的指定类型,那么 TypeScript 会依照类型推论(Type Inference)的规则推断出一个类型
如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成 any 类型而完全不被类型检查
枚举和接口
接口
面向对象语言中,接口(Interfaces)是一个很重要的概念,它是对行为的抽象,而具体如何行动需要由类(classes)去实现(implement)
TypeScript 中的接口是一个非常灵活的概念,除了可用于对类的一部分行为进行抽象以外,也常用于对「对象的形状(Shape)」进行描述
栗子
interface Person {
name: string;
age: number;
}
let person: Person = {
name: "Tom",
age: 123,
};
定义的变量比接口少了一些属性是不允许的
多一些属性也是不允许的
赋值的时候,变量的形状必须和接口的形状保持一致
interface Person {
name: string;
}
let person: Person = {
name: "Tom",
age: 123,
};
/*
Type '{ name: string; age: number; }' is not assignable to type 'Person'.
Object literal may only specify known properties, and 'age' does not exist in type 'Person'.
*/
import React from "react";
import "./App.css";
interface Todo {
content: string;
user: string;
time: string;
isCompleted: boolean;
}
function App() {
const todo: Todo = {
content: "用于对函数、类等进行结构类型检查",
user: "mRcfps",
time: "2020年3月2日 19:34",
isCompleted: false,
};
return <div className="App">{todo.content}</div>;
}
export default App;
可选属性
interface Todo {
content: string;
user: string;
time?: string;
isCompleted: boolean;
}
只需要在属性类型修饰冒号左边加一个问号就可以了,这个时候我们就告诉 TS 编译器这个 time
属性是可选的一个类型
只读属性
只读属性的添加就是在属性之前加上 readonly
关键字,就可以将 Interface 中的属性标志为已读的
interface Todo {
content: string;
readonly user: string;
isCompleted: boolean;
}
当我们进行上面的修改操作之后,编辑器内会报错
枚举
枚举是 TS 中独有的概念,在 JS 中没有,主要用于帮助定义一系列命名常量,常用于给一类变量做类型注解,它们的值是一组值里面的某一个
enum UserId {
Wahaha,
Telunsu,
Mengniu,
Huasheng,
}
let user = UserId.Wahaha;
user = "哇哈哈";
//Type '"哇哈哈"' is not assignable to type 'UserId'
数字类型枚举与数字类型
数字类型枚举,允许我们将数字类型或者其他任何与数字类型兼容的类型赋值给枚举类型的实例
enum UserId {
Wahaha,
Telunsu,
Mengniu,
Huasheng,
}
let user = UserId.Wahaha;
user = 119;
字符串枚举
enum Env {
PASSWORD = "qwerdf12",
PORT = "8080",
IP = "192.168.0.0",
}
let url = Env.IP;
//console.log(url) 192.168.0.0
数组的类型
在 TypeScript 中,数组类型有多种定义方式,比较灵活。
[类型 + 方括号]来表示数组
let test: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 9999999];
数组的项中不允许出现其他的类型
let test: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, "9999999"];
/*
Type 'string' is not assignable to type 'number'
*/
数组泛型
let test: Array<number> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 999999];
用接口表示数组
interface numberArray {
[index: number]: number;
}
let test: numberArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 9999999];
类数组
类数组(Array-like Object)不是数组类型
function sum() {
let args: number[] = arguments;
}
/*
* Type 'IArguments' is missing the following properties from type 'number[]': pop, push, concat, join, and 26 more.
*/
any 在数组中的应用
let test: any[] = [
"cxk",
{ website: "https://521wangdong.github.io/blog/typescript/" },
];
函数的类型
函数声明
在 JavaScript 中,有两种常见的定义函数的方式——函数声明(Function Declaration)和函数表达式(Function Expression)
一个函数有输入和输出,要在 TypeScript 中对其进行约束,需要把输入和输出都考虑到,其中函数声明的类型定义较简单
function sum(x: number, y: number): number {
return x + y;
}
输入多余的(或者少于要求的)参数,是不被允许的
function sum(x: number, y: number): number {
return x + y;
}
sum(1);
/*
Expected 2 arguments, but got 1. TS2554
*/
类型断言
类型断言(Type Assertion)可以用来手动指定一个值的类型
值 as 类型
interface Cat {
name: string;
run(): void;
}
interface Fish {
name: string;
swin(): void;
}
function isFish(animal: Cat | Fish) {
if (typeof (animal as Fish).swin === "function") {
return true;
}
return false;
}
元组
数组合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象
栗子
let arr: [string, number] = ["Wahaha", 18];
泛型
是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性
function createArray<T>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
createArray<string>(3, "x"); // ['x', 'x', 'x']