文章目录
什么是TypeScript ?
- TypeScript简称TS
- TS和JS之间的关系其实就是Less/Sass和CSS之间的关系
- 就像Less/Sass是对CSS进行扩展一样, TS也是对JS进行扩展
- 就像Less/Sass最终会转换成CSS一样,我们编写好的TS代码最终也会换成JS
- TypeScript是JavaScript的超集,因为它扩展了JavaScript,有JavaScript没有的东西
- 硬要以父子类关系来说的话,TypeScript是JavaScript子类,继承的基础上去扩展
为什么需要TypeScript ?
- 简单来说就是因为JavaScript是弱类型, 很多错误只有在运行时才会被发现
- 而TypeScript提供了一套静态检测机制, 可以帮助我们在编译时就发现错误
TypeScript数据类型
基础类型
八种内置类型:string、number、boolean、undefined、null、object、bigint、symbol
let str: string = "jimmy";
let num: number = 24;
let bool: boolean = false;
let u: undefined = undefined;
let n: null = null;
let obj: object = {x: 1};
let big: bigint = 100n;
let sym: symbol = Symbol("me");
默认情况下 null
和 undefined
是所有类型的子类型。 就是说你可以把 null
和 undefined
赋值给其他类型。
// null和undefined赋值给string
let str:string = "666";
str = null
str= undefined
// null和undefined赋值给number
let num:number = 666;
num = null
num= undefined
// null和undefined赋值给object
let obj:object ={};
obj = null
obj= undefined
// null和undefined赋值给Symbol
let sym: symbol = Symbol("me");
sym = null
sym= undefined
// null和undefined赋值给boolean
let isDone: boolean = false;
isDone = null
isDone= undefined
// null和undefined赋值给bigint
let big: bigint = 100n;
big = null
big= undefined
虽然 number
和 bigint
都表示数字,但是这两个类型不兼容。
let big: bigint = 100n;
let num: number = 6;
big = num;
num = big;
// 会抛出一个类型不兼容的 ts(2322) 错误。
其他类型
1.Array
对数组类型的定义有两种方式:
let arr: string[] = ["1","2"];
let arr2: Array<string> = ["1","2"];
定义联合类型数组:
let arr: (number | string)[];
// 表示定义了一个名称叫做arr的数组,
// 这个数组中将来既可以存储数值类型的数据, 也可以存储字符串类型的数据
arr3 = [1, 'b', 2, 'c'];
定义指定对象成员的数组:
// interface是接口,后面会讲到
interface Arrobj{
name: string,
age: number
}
let arr3: Arrobj[]=[{name:'jimmy',age:22}]
2.函数
函数声明:
function sum(x: number, y: number): number {
return x + y;
}
函数表达式:
let mySum: (x: number, y: number) => number = function (x: number, y: number): number {
return x + y;
};
用接口定义数据类型:
interface SearchFunc{
(source: string, subString: string): boolean;
}
其他特性:
// 可选参数
function buildName(firstName: string, lastName?: string) {
if (lastName) {
return firstName + ' ' + lastName;
} else {
return firstName;
}
}
let tomcat = buildName('Tom', 'Cat');
let tom = buildName('Tom');
// 默认参数
function buildName(firstName: string, lastName: string = 'Cat') {
return firstName + ' ' + lastName;
}
let tomcat = buildName('Tom', 'Cat');
let tom = buildName('Tom');
// 剩余参数
function push(array: any[], ...items: any[]) {
items.forEach(function(item) {
array.push(item);
});
}
let a = [];
push(a, 1, 2, 3);
3.元组
众所周知,数组一般由同种类型的值组成,但有时我们需要在单个变量中存储不同类型的值,这时候我们就可以使用元组。在 JavaScript中是没有元组的,元组是 TypeScript 中特有的类型,其工作方式类似于数组。
元组最重要的特性是可以限制数组元素的个数和类型,它特别适合用来实现多值返回。 元组用于保存定长定数据类型的数据
let x: [string, number];
// 类型必须匹配且个数必须为2
x = ['hello', 10]; // OK
x = ['hello', 10,10]; // Error
x = [10, 'hello']; // Error
元组的特性
// 元组的解构赋值
let employee: [number, string] = [1, "Semlinker"];
let [id, username] = employee;
console.log(`id: ${id}`);
console.log(`username: ${username}`);
// 元组的可选元素
let optionalTuple: [string, boolean?];
optionalTuple = ["Semlinker", true];
console.log(`optionalTuple : ${optionalTuple}`);
optionalTuple = ["Kakuqo"];
console.log(`optionalTuple : ${optionalTuple}`);
// -->
optionalTuple : Semlinker,true
optionalTuple : Kakuqo
// 元组的剩余参数
type RestTupleType = [number, ...string[]];
let restTuple: RestTupleType = [666, "Semlinker", "Kakuqo", "Lolo"];
console.log(restTuple[0]);
console.log(restTuple[1]);
4.Void
void
表示没有任何类型,和其他类型是平等关系,不能直接赋值:
你只能为它赋予null
和undefined
(在strictNullChecks
未指定为true
时)。声明一个void
类型的变量没有什么大用,我们一般也只有在函数没有返回值时去声明。
let a: void;
let b: number = a; // Error
5.Never
never
类型表示的是那些永不存在的值的类型。
值会永不存在的两种情况:
- 如果一个函数执行时抛出了异常,那么这个函数永远不存在返回值(因为抛出异常会直接中断程序运行,这使得程序运行不到返回值那一步,即具有不可达的终点,也就永不存在返回了);
- 函数中执行无限循环的代码(死循环),使得程序永远无法运行到函数返回值那一步,永不存在返回。
// 异常
function err(msg: string): never { // OK
throw new Error(msg);
}
// 死循环
function loopForever(): never { // OK
while (true) {};
}
在 TypeScript 中,可以利用 never
类型的特性来实现全面性检查,具体示例如下:
type Foo = string | number;
function controlFlowAnalysisWithNever(foo: Foo) {
if (typeof foo === "string") {
// 这里 foo 被收窄为 string 类型
} else if (typeof foo === "number") {
// 这里 foo 被收窄为 number 类型
} else {
// foo 在这里是 never
const check: never = foo;
}
}
-->
type Foo = string | number | boolean;
// else 分支的 foo 类型会被收窄为 boolean 类型,
// 导致无法赋值给 never 类型,这时就会产生一个编译错误。
结论:使用 never 避免出现新增了联合类型没有对应的实现,目的就是写出类型绝对安全的代码。
6.Any
在 TypeScript 中,任何类型都可以被归为 any
类型。这让 any
类型成为了类型系统的顶级类型
如果是一个普通类型,在赋值过程中改变类型是不被允许的:
let a: string = 'seven';
a = 7;
// TS2322: Type 'number' is not assignable to type 'string'.
但如果是 any
类型,则允许被赋值为任意类型。
let a: any = 666;
a = "Semlinker";
a = false;
a = 66
a = undefined
a = null
a = []
a = {}
在许多场景下,这太宽松了。使用 any
类型,可以很容易地编写类型正确但在运行时有问题的代码。如果我们使用 any
类型,就无法使用 TypeScript 提供的大量的保护机制。请记住,any
是魔鬼!尽量不要用 any
。
为了解决 any
带来的问题,TypeScript 3.0 引入了 unknown
类型。
7.Unknown
unknown
与any
一样,所有类型都可以分配给unknown
:
let notSure: unknown = 4;
notSure = "maybe a string instead"; // OK
notSure = false; // OK
unknown
与any
的最大区别是: 任何类型的值可以赋值给any
,同时any
类型的值也可以赋值给任何类型。unknown
任何类型的值都可以赋值给它,但它只能赋值给unknown
和any
let notSure: unknown = 4;
let uncertain: any = notSure; // OK
let notSure: any = 4;
let uncertain: unknown = notSure; // OK
let notSure: unknown = 4;
let uncertain: number = notSure; // Error
8.Object
object
表示非原始类型,也就是除number
,string
,boolean
,symbol
,null
或undefined
之外的类型。使用object
类型,就可以更好的表示像Object.create
这样的API
declare function create(o: object | null): void;
create({ prop: 0 }); // OK
create(null); // OK
create(42); // Error
create("string"); // Error
create(false); // Error
create(undefined); // Error
9.枚举
enum
类型是对JavaScript标准数据类型的一个补充,使用枚举类型可以为一组数值赋予友好的名字
enum Color {
Green = 2,
Red = 3,
Blue = 5,
}
let color: Color = Color.Green
类型断言
类型断言用于手动指定一个值的类型。
类型断言有两种形式:
第一种:“尖括号”语法
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
第二种:as
语法
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;
以上两种是等价的,都是将any
类型的someValue
断言为string
类型。
注意:当在TypeScript里使用JSX
时,只有as
语法断言是被允许的。
接口
接口定义
首先通过接口来描述一个栗子:必须包含一个label
属性且类型为tring
// 接口
interface ValueStatus {
label: string;
}
function getStatus(obj: ValueStatus) {
console.log(obj.label);
}
let myObj = { size: 10, label: 'Size 10 Object' };
getStatus(myObj);
ValueStatus
就好比一个接口的名字,用来描述要求,(有一个label
属性且类型为string
的对象)。
类型检查器不会去检查属性的顺序,只要相应的属性存在并且类型也是对的就可以
可选属性
接口里的属性不全都是必需的。 有些是只在某些条件下存在,或者根本不存在。
可选属性的接口和普通接口定义差不多,只是在可选属性名后面加个?问号:
interface MyOrder {
name: string;
price?: string;
count?: number;
}