TypeScript
为 JavaScript 添加了类型系统,并且适用于任何规模的项目。
基础数据类型
boolean 、number 、string 、undefined 、null 、symbol 、bigint
主要说明前5种
// 布尔值
let isboolean : boolean = false;
// 数值
let isnumber : number = 12;
// 字符串
let str = "word"
let isstring : string = '123';
// 也可以使用字符串模板
let isstring2 : string = `你好${str}`;
// null 和undefined
let u : undefined = undefined
let n: null = null
// 空值 javascript 没有空值这个概念 void
// 在typescript 中可以使用 void 表示没有任何返回值的函数
function alertName() :void{
alert("My name is wf")
}
// 声明一个void类型的变量没有什么用,因为你只能将他赋值为undefined 和null
let unusable :void = undefined;
任意值
通过 Any 关键字来表示允许赋值为任意类型。
已经定义过的变量类型,在重新赋值的过程中是不允许改变数据类型的!
例如:
let str: string = 'seven';
str = 7 //报错
但如果是 any 类型 那么就可以改变
// 任意值 Any
// any类型就不会报错
let str :any = 'seven';
str = 7
通过任意值声明的变量可以访问任何属性和方法
声明一个变量为任意值的时候,对它做任何的操作,返回的内容类型全部都是任意值。
// 属性
let any1: any = '你好';
console.log(any1.myName);
console.log(any1.myName.firstName);
// 方法
let any2: any = '很好';
any2.setName('非常好');
any2.setName('非常好').sayHello();
any2.myName.setFirstName('good');
如果声明变量时没有指定它的类型,那么它会被自动识别为任意值类型:
let anystr;
anystr = '123';
anystr = 123
类型推论
声明变量没有明确的指定类型,TypeScript 会通过强大的类型推论规则推断出一个类型。
例如:
// 一般声明变量
let num: number = 100
// 通过类型推论可以这样写
let nums = 100
注意:如果定义变量时没有赋值 ,那么不管之后有没有赋值该变量都会被推断为 any 任意类型。
联合类型
联合类型就是在特殊情况下一个变量可以是多种类型
通过 | 管道符连接和分割多个类型
例如:
let union : number | string = "123"; // 值为字符串类型
// 重新赋值为数字类型
union = 123
union 变量的类型可以是 number 、string,但是不可以是其他类型。
需要注意的是:只可以访问联合类型的所有类型里共有的属性或者方法。
// 报错 number 类型没有 lenght
function fn(params:string | number) : number {
return params.length
}
// 两个类型中都有 toString
function fn2(params:string | number) : string {
return params.toString()
}
对象类型——>接口
通过 Interface 关键字来定义对象的类型。
定义接口时要使用 ; 分号来分割而不是 , 逗号
例如:
interface person {
name: string;
age:number
}
let tom : person = {
name :"tom",
age:20
}
注意:定义的变量比接口少了一些属性或者多一些属性是不允许的,我们在赋值时需要做到变量的形状必须与接口形状保持一致。
interface person {
name: string;
age:number
}
// 报错
let tom : person = {
name :"tom",
}
// 报错
let tom : person = {
name :"tom",
age:20,
mode:213,
}
可选属性
通过 "?" 来实现可选属性。
那么在一些特殊的情况下,需要不完全匹配接口的形状,这时可以通过可选属性来实现。
// 可选属性 '?'
interface per {
name: string;
age?: number
}
let obj : per = {
name: "wf"
}
意思就是 虽然我创建了一个属性类型但是我也可以不去使用它,这个 age 属性就是一个可选属性。此时依旧不允许添加没有定义的属性,例如:我没有添加 moble 属性,那么我是不可以使用 moble 属性的
任意属性
有时我们希望接口中有任意的属性可以使用 [propName: 类型] 定义
这里需要注意的是我一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集
interface arbitrarily {
name : string; // 确定属性
age ?: number; // 可选属性
[propName:string] : any; // 任意属性
}
一个接口中只能定义一个任意属性。如果接口中有多个类型的属性,可以在任意属性中使用联合类型 例如:
interface arbitrarily {
name : string; // 确定属性
age ?: number; // 可选属性
[propName:string] : number | string; // 任意属性
}
只读属性
只允许读,不允许对该值进行操作的属性。
通过 readonly 来定义一个只读属性。
注意:只读的约束存在于 第一次给对象赋值的时候,而不是第一次给只读属性辅助的时候。
interface asda{
readonly id: number;
name : string;
age ?: number
}
数组的类型
类型 + 中括号
最简单的方法就是通过 类型 + [] 来表示数组
注意:这样定义数组该数组的每一项中不允许出现其他的数据类型。
例如:
// 声明一个正确的数组
let arr : number[] = [1,12,123,123];
// 错误的演示
// let arr : number[] = [1,12,123,123,'123'];
数组泛型
那么声明数组也可以通过 数组泛型的方式 Array<elemType> 来表示数组:
let array : Array<string> = ['123','123'];
用接口表示数组
interface NumberArray {
[index: number] :number
}
let array2 : NumberArray = [1,2,3,123]
类数组
类数组不是数组类型,比如 arguments
function sum() {
let args: {
[index: number]: number;
length: number;
callee: Function;
} = arguments;
}
在这个例子中,我们除了约束当索引的类型是数字时,值的类型必须是数字之外,也约束了它还有 length
和 callee
两个属性。
常用的类数组都有自己的接口定义,如 Iarguments 、NodeList 、HTMLCollection 等
function sum() {
let args: IArguments = arguments;
}
any 在数组中的应用
通过 any[] 来声明的数组可以有任意类型
let list : any[] = ['wf',{name:'wf'},100]
函数的类型
函数声明
在一个函数中 有输入有输出,在 TypeScript 中对函数进行约束,需要把输入、输出都考虑到,其中函数声明的类型定义简单一些:
function fn3(a : number,b : number) :number {
return a + b
}
注意:这里输入多余或者少于要求的参数都是不被允许的。
错误例子:
// 错误例子
function fn3(a : number,b : number) :number {
return a + b
}
fn3(1,2,3)
fn3(1)
函数表达式
let fn4 : (a : number, b : number) => number = function(a : number, b : number): number {
return a + b
}
注意不要混淆了 TypeScript 中的 => 和 ES6 中的 =>。
在 TypeScript 的类型定义中 => 用来表示函数的定义,左边是输入类型,需要使用括号括起来,右边是输出的类型。
用接口定义函数的形状
使用接口的方式定义一个函数需要符合的形状
interface SearchFn {
(source: string, subString: string): boolean;
}
let mySearch: SearchFn;
mySearch = function(source: string, subString: string) {
return source.search(subString) !== -1;
}
采用函数表达式|接口定义函数的方式时,对等号左侧进行类型限制,可以保证以后对函数名赋值时保证参数个数、参数类型、返回值类型不变。
可选参数
函数中多余或者少于要求的参数,是不被允许的,可以通过可选参数来实现 "?"。
与接口中的可选属性类似。
注意:可选参数后面是不允许再出现必选参数的。
function buildName (firstName: string, lastName?: string) {
if(lastName) {
return firstName + ' ' + lastName;
} else {
return firstName;
}
}
let tomcat = buildName('Tom','Cat')
let toms = buildName('Tom')
参数默认值
TypeScript 会将添加了默认值的参数识别为可选参数
此时就不受 " 可选参数必须接在必需参数后面 " 的限制了:
function buildName (firstName: string = 'tom', lastName: string) {
if(lastName) {
return firstName + ' ' + lastName;
} else {
return firstName;
}
}
let tomcat = buildName('Tom','Cat')
let toms = buildName(undefined,'Tom')
剩余参数
可以通过数组的类型来定义它:
function push(array: any[], ...items: any[]) {
items.forEach(function(item) {
array.push(item);
});
}
let a = [];
push(a, 1, 2, 3);
重载
比如,我们需要实现一个函数 reverse
,输入数字 123
的时候,输出反转的数字 321
,输入字符串 'hello'
的时候,输出反转的字符串 'olleh'
。
function reverse(x: number): number;
function reverse(x: string): string;
function reverse(x: number | string): number | string | void {
if (typeof x === 'number') {
return Number(x.toString().split('').reverse().join(''));
} else if (typeof x === 'string') {
return x.split('').reverse().join('');
}
}
上例中,我们重复定义了多次函数 reverse
,前几次都是函数定义,最后一次是函数实现。在编辑器的代码提示中,可以正确的看到前两个提示。
注意,TypeScript 会优先从最前面的函数定义开始匹配,所以多个函数定义如果有包含关系,需要优先把精确的定义写在前面。
类型断言
明天更新。。。。