环境配置
需要安装的包:
- typescript
- ts-node(可以直接运行ts文件)
npm i typescript ts-node -g
注意事项:
- 用ts-node运行ts文件的时候可能会报 Cannot find module '@types/node/package.json',如果出现全局安装一下
tslib,@types/node这两个包即可。 - 如果直接通过vscode右上角的运行按钮运行ts文件,以上所说的依赖包必须全局安装
日常类型
基础类型
string, number, boolean, null,undefined
数组类型
-
「类型 + 方括号」表示法
let fibonacci: number[] = [1, 1, 2, 3, 5]; -
泛型方式
let arr:Array<number> = [] let arr = new Array<string>() -
接口方式
interface NumberArray { [index: number]: number; } let fibonacci: NumberArray = [1, 1, 2, 3, 5]; -
声明类数组
interface ArgsArray { [index: number]: number; length: number; callee: Function; } function sum() { let args: ArgsArray = arguments; }
any/unkown
any - 任意的类型
unkown - 未知类型
let a:any
a = 1 // OK
a = 'string' // OK
let b:unkown
b = 1 // OK
b = 'string' // OK
let c:number = b // Error
这两个类型的使用方式大同小异,不同的是用unkown声明的变量不能赋值给别的变量
noImplicitAny
在ts.config中此项配置为true时,则需要显式添加any类型,反则为false的时候会隐式添加
// noImplicitAny=true
function a(x){} // Error
function a(x:any){} // Ok
// noImplicitAny=false
function a(x){} // OK
类型断言 (assertion)
类型断言(Type Assertion)可以用来手动指定一个值的类型。在你确定某个值的时候即可使用断言
语法
//值 as 类型
num as number
//<类型>值
<number>num
使用方式
// 案例1
interface Cat {
name: string;
run(): void;
}
interface Fish {
name: string;
swim(): void;
}
function swim(animal: Cat | Fish) {
(<Fish>animal).swim()
}
// 案例2
class ApiError extends Error {
code: string = '00';
}
class HttpError extends Error {
statusCode: number = 200;
}
function isApiError(error: Error) {
if (typeof (error as ApiError).code === 'string') {
return true;
}
return false;
}
非空断言
当变量在上下文中无法判断类型的时候,表达式后缀加上
!即可用于断言,该变量必定不会是null或undefined
// 不使用非空断言下面的代码会报错
function sum(x: number | null | undefined, y: number | null | undefined) {
return x + y
}
// 使用后
function sum(x: number | null | undefined, y: number | null | undefined) {
return x! + y!
}
// 也可以结合as一起做断言
function sum(x: number | string | null | undefined, y: number | null | undefined) {
return (x as number)! + y!
}
接口(interface)
语法
interface 接口名称 {
属性:属性类型
}
使用方式
// 声明
interface Person {
name: string;
age: number;
getName() : string //定义函数
}
// 使用
let ivan :Person = {
name:'ivan',
age:18,
getName(){
return this.name
}
}
任意属性
示例代码中任意属性的类型是string,其值的类型可为string或number。那么Person接口中就不能定义除string, numbe以外的类型否则就会报错。
ivan.address = '广东珠海'如果没有任意属性的情况下这段代码是会报错的
语法:
interface Person {
[任意名称:属性类型]:属性值的类型
}
示例:
interface Person {
name: string;
isBoy:boolean; // Error
[propName: string]: string | number // 任意属性
}
let ivan :Person = {
name:'ivan',
age:18, // OK
isChild:true, // Error
}
ivan.address = '广东珠海' // OK
注意:一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集。
只读属性
设置只读后该属性只允许读取行为,不允许进行赋值
语法:
interface Person {
readonly 属性:类型
}
示例:
interface Person {
readonly id: number;
}
let ivan :Person = {
id:1, // OK
}
ivan.id = 1 // Error
注意:是约束对象赋值,而不是约束对属性赋值
接口继承接口
语法:
interface 接口1 extendx 接口2 {
...
}
示例:
interface Alarm {
alert(): void;
}
interface LightableAlarm extends Alarm {
lightOn(): void;
lightOff(): void;
}
class Door implements LightableAlarm{
lightOn(): void {
throw new Error("Method not implemented.")
}
lightOff(): void {
throw new Error("Method not implemented.")
}
alert(): void {
throw new Error("Method not implemented.")
}
}
接口继承类
当我们声明
interface Point3d extends Point时,Point3d继承的实际上是类Point的实例的类型。换句话说,可以理解为定义了一个接口
Point3d继承另一个接口PointInstanceType。所以「接口继承类」和「接口继承接口」没有什么本质的区别。
语法:
interface 接口1 extendx 类1 {
...
}
示例:
class Point {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
}
interface PointInstanceType {
x: number;
y: number;
}
// 等价于 interface Point3d extends PointInstanceType
interface Point3d extends Point {
z: number;
}
let point3d: Point3d = {x: 1, y: 2, z: 3};
function printPoint(p: PointInstanceType) {
console.log(p.x, p.y);
}
printPoint(new Point(1, 2));
注意:接口只继承类的属性和方法,并不会继承constructor
泛型(generics)
泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
简单的方式
函数名后添加了 <T>,其中 T 用来指代任意输入的类型,在后面的输入 value: T 和输出 Array<T> 中即可使用了。在调用函数的时候即可传入泛型的类型,如果不写则会按照参数的类型
function createArrayG<T>(value:T):Array<T>{
let arr = []
arr = Array(5).fill(value)
return arr
}
console.log(createArrayG<number>(1)) // 输出:[1,1,1,1,1]
泛型中继承
当T继承某个number后,那么调用函数的时候参数必须是number类型
function createArrayG2<T extends number>(value:T):Array<T>{
let arr = []
arr = Array(5).fill(value)
return arr
}
console.log(createArrayG2(1)) // OK
console.log(createArrayG2('1')) // Error
多个类型参数
泛型中可以定义多个不同的类型参数
function swap<T, U>(a: T, b: U): [U, T] {
//return [a, b]; // Error
return [b, a];
}
console.log(swap<number,string>(7, 'seven')); // OK
console.log(swap<number,string>('seven',7)); // Error
console.log(swap<number,string>('seven',true)); // Error
泛型约束
使用泛型变量的时候是无法知道该变量拥有什么属性和方法,假设你想通过length去查看变量的长度,ts会直接报错。
如果需要这样写的话则需要先定义一个interface然后声明一个length属性,然后通过泛型继承这个接口。
示例:
interface ILength {
length: number;
}
// good
function loggingIdentity<T extends ILength>(arg: T) {
console.log(arg.length);
}
// bad
function loggingIdentity<T>(arg: T) {
console.log(arg.length);
}
loggingIdentity(1) // Error
loggingIdentity('hello'); // OK
注意:调用这个loggingIdentity时,arg必须要有length这个属性否则会直接报错
泛型接口
示例:
/* 方式1 */
interface CreateArrayFunc {
<T>(length: number, value: T): Array<T>;
}
let createArrayIn: CreateArrayFunc;
createArrayIn = function <T>(length: number, value: T): Array<T> {
let result: T[] = [];
result = Array(length).fill(value);
return result;
};
console.log(createArrayIn<number>(3, 1));
/* 方式2 */
interface CreateArrayFunc2<T> {
(length: number, value: T): Array<T>;
}
let createArrayIn2: CreateArrayFunc2<any>;
createArrayIn2 = function <T>(length: number, value: T): Array<T> {
let result: T[] = [];
result = Array(length).fill(value);
return result;
};
console.log(createArrayIn2(3, 1));
// 对象的接口定义
interface CreateObj<T> {
name: T
}
let createObjI:CreateObj<string>
注意:当泛型参数提前到接口名上后,在使用泛型接口的时候,需要定义泛型的类型
泛型类
示例:
class GenericNumber<T> {
zeroValue: T | undefined;
add!: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function (x, y) {
return x + y;
};
console.log(myGenericNumber.add(1, 2));
注意:如果属性用到了T,则这个属性需要加多一个undefined类型,或者使用!非空断言!
泛型参数的默认类型
示例:
function createArrayInf<T = string>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
console.log(createArrayInf(5, 1));