TypeScript安装
TypeScript 的命令行工具安装方法如下:npm install -g typescript
以上命令会在全局环境下安装 tsc 命令,安装完成之后,我们就可以在任何地方执行 tsc 命令了
直接运行ts代码,需要手动安装插件:
//全局安装ts-node
npm i -g ts-node
//在项目目录下,生成tsconfig.json
tsc --init
npm安装package.json中的依赖 npm i
package.json文件内容
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "1.js",
"directories": {
"test": "test"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@types/node": "^20.10.4",
"ts-node": "^10.9.2",
"tslib": "^2.6.2",
"typescript": "^5.2.2"
}
}
各类型定义
简单类型
let flag: boolean = false;
let num: number = 15;
let str: string = "abc";
let u: undefined = undefined;
let n: null = null;
//声明的变量有多种类型--联合类型声明
let id: number | string = 10;
//任意类型
let x: any = true;
x = 111;
x = "222";
引用类型
//数组定义
let arr = [1, 2, 3, "4"];
let arr1: number[] = [1, 2, 3];
let arr2: string[] = ["A", "B"];
let arr3: (number | string)[] = [1, 2, 3, "4"];//联合类型声明
let arr4: any[] = [1, 2, 3, "4"];
//数组泛型
let arr5: Array<number> = [1, 2, 3];
let arr6: Array<number | string> = [1, 2, 3, "4"];
接口
接口(Interfaces)可以用于对「对象的形状(Shape)」进行描述。声明对象的模版
//对象定义
//定义接口,首字母大写
interface Person {}
class Person {}
//开发中使用IPerson:区分class
interface IPerson {
//变量
id: number;
name: string;
age?: number;//可选属性
[propName: string]: any; //任意属性,需要注意的是,一旦定义了任意属性,那么确定属性和可选属性都必须是它的子属性
}
//id和name受到IPerson的约束
let obj: IPerson = {
id: 1,
name: "jack",
};
let Item1: IPerson[] = [
{ id: 1, name: "jack" },
{ id: 1, name: "jack" },
];
let Item2: Array<IPerson> = [
{ id: 1, name: "jack" },
{ id: 1, name: "jack" },
];
接口中定义方法:
//接口中定义方法
interface IPerson2 {
name: string;
age: number;
say(); //定义方法
action(v: number): number; //定义方法
}
let o: IPerson2 = {
name: "jack",
age: 20,
say() {},
action(v) {
return this.age;
},
};
//接口修饰(约束)方法
interface ISum {
(n1: number, n2: number): number;
}
let sum: ISum = (n1, n2) => n1 + n2;
多层级结构:
interface IResult {
id: number;
value: number;
}
interface ITest {
code: number;
msg?: string;
result: IResult[];
}
let o2: ITest = {
code: 2000,
msg: "success",
result: [
{
id: 1,
value: 100,
},
],
};
接口的继承
interface IPerson3 {
id: Number;
name: string;
age?: number;
say();
}
interface IAction extends IPerson3 {
action(v: number, v2: number): number;
}
let o3: IAction = {
name: "jack",
id: 20,
say() {},
action(v) {
return this.age;
},
};
函数类型
一个函数有输入和输出,要在 TypeScript 中对其进行约束,需要把输入和输出都考虑到
//函数类型定义--函数有输入和输出类型
function sum1(x: number, y: number): number {
return x + y;
}
//输出无返回值
function sum2(x: number, y: number): void {
console.log(x + y);
}
//输入参数定义默认值
function sum3(x: number = 1, y: number = 2): number {
return x + y;
}
//输入参数选填参数.?选填
function sum4(x: number = 1, y?: number): number {
return x + (y || 4);
}
const fn5 = function ({ id, name }: { id: number; name: string }): {
pid: number;
title: string;
} {
return { pid: id, title: name };
};
const f6 = ({
id,
name,
}: {
id: number;
name: string;
}): { pid: number; title: string } => {
return { pid: id, title: name };
};
泛型
泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定 类型的一种特性。泛型变量T , T表示任何类型
什么时候需要定义泛型函数?要创建一个可重用的组件,其中的数据类型就必须要兼容很多的类型
function fn1(a: number, b: number): number[] {
return [a, b];
}
function fn2(a: string, b: string): string[] {
return [a, b];
}
//fn1和fn2很类似,使用泛型定义方法
function fn<T>(a: T, b: T): Array<T> {
return [a, b];
}
fn(10, 20);
fn("10", "20");
泛型约束
function f4(arg: T): T {
console.log(arg.length); // 错误: T不存在length属性 比如数值等
}
使用了 extends 约束了泛型 T 必须符合接口 LengthN 的形状,也就是必须包含 length 属性
interface ILength {
length: number;
}
function fn4<T extends ILength>(str: T): number {
return str.length;
}
let o5: ILength = {
length: 6,
};
fn4(o5);
fn4<Array<number>>([1, 2.3]); //Array<number>也是有length属性的
fn4<{ id: number; length: number }>({ id: 1, length: 10 }); //{ id: number; length: number }包含length属性的接口约束
interface INamed {
name: string;
[propName: string]: any;
}
//要求传入的参数必须有name属性
function f5<T extends INamed>(x: T): string {
return x.name;
}
f5({ name: "jack", age: 18 });
f5<INamed>({ name: "jack", age: 18 });
/*************************多类型泛型****************************** */
interface IMultiply<T, U> {
first: T;
second: U;
}
const o6: IMultiply<Number, string> = {
first: 1,
second: "1",
};
/*****************泛型在函数中的应用******************** */
//函数声明
function f6<T>(n1: T, n2: T): T[] {
return [n1, n2];
}
//函数表达式
let f7 = function <U>(n1: U, n2: U): Array<U> {
return [n1, n2];
};
//泛型&箭头函数
let f8 = <U>(n1: U, n2: U): U[] => {
return [n1, n2];
};
/*************************多类型泛型****************************** */
interface IMultiply<T, U> {
first: T;
second: U;
}
const o6: IMultiply<Number, string> = {
first: 1,
second: "2",
};
/**
* 扩展:定义一个函数,传入长度和值,返回数组(数组的长度是传入的长度,数组的值是传入的参数)
* **/
let createArr = function <T>(len: number, v: T): T[] {
let arr: T[] = [];
for (let i = 0; i < len; i++) {
arr[i] = v;
}
return arr;
};
interface ICreateArr {
<T>(len: number, v: T): T[];
}
let createArr1: ICreateArr = <T>(len, v) => {
let arr: T[] = [];
for (let i = 0; i < len; i++) {
arr[i] = v;
}
return arr;
};
类
class Cat {
name: string;//必须要声明
color: string;//必须要声明
constructor(name, color) {
this.name = name;
this.color = color;
}
eat(v: string) {
return v;
}
}
let cat = new Cat("jack", "black");
//类也可以受到接口的约束
interface IFeatures {
name: string;
age?: number;
action(): string;
}
//接口中的属性和方法,类中必须要实现
class Person implements IFeatures {
name: string;
age: number;
//构造器用到的参数,要在类中提前声明
constructor(name, age) {
this.name = name;
this.age = age;
}
action(): string {
return this.name;
}
}
类单继承多实现
//类也可以受到接口的约束
interface IFeatures {
name: string;
age?: number;
action(): string;
}
//接口中的属性和方法,类中必须要实现
class Person implements IFeatures {
name: string;
age: number;
//构造器用到的参数,要在类中提前声明
constructor(name, age) {
this.name = name;
this.age = age;
}
action(): string {
return this.name;
}
}
//类继承&实现
interface IWarning {
sing(ball: string): string;
}
interface ILight {
lightOn();
lightOff(): boolean;
}
class Door {
type: string;
constructor(type) {
this.type = type;
}
}
class SecurityDoor extends Door implements IWarning {
constructor(type) {
super(type);
}
sing(ball: string): string {
return "";
}
}
class Car implements IWarning, ILight {
height: number;
color: string;
constructor(height, color) {
this.height = height;
this.color = color;
}
lightOn() {}
lightOff(): boolean {
return true;
}
sing(ball: string): string {
return "";
}
}
修饰符
public&private&protected
public 修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public 的
private 修饰的属性或方法是私有的,不能在声明它的类的外部访问,子类也不能进行访问
protected 修饰的属性或方法是受保护的,它和 private 类似,区别是它在子类中也是允许被访问的
/*****************private修饰的属性或方法是私有的,不能在声明它的类的外部访问*************** */
class Cat2 {
private name: string;
private color: string;
constructor(name: string, color: string) {
this.name = name;
this.color = color;
};
private say():string{
return "";
}
}
let cat2 = new Cat2("jack", "black");
cat2.name; //属性“name”为私有属性,只能在类“Cat2”中访问。ts(2341)
cat2.say();//属性“say”为私有属性,只能在类“Cat2”中访问。ts(2341)
//private修饰的属性和方法在子类中也是访问不到的
class Test extends Cat2 {
constructor(name: string, color: string) {
super(name, color);
}
}
let test = new Test("jack", "red");
test.name;//属性“name”为私有属性,只能在类“Cat2”中访问。ts(2341)
通过公共方法获取私有属性:
class Employee {
protected salary: number;
public name: string;
constructor(salary: number, name: string) {
this.name = name;
this.salary = salary;
}
protected say(): string {
return "";
}
public getSalary(): number {
return this.salary;
}
}
let emploee = new Employee(1000, "jack");
let s: number = emploee.getSalary();
console.log(s);//1000
静态修饰符static
属性或者方法不需要实例化
class Employee2 {
static salary: number = 1000;
public name: string;
constructor(name: string) {
this.name = name;
}
protected say(): string {
return "";
}
public getSalary(): number {
return Employee2.salary;
}
}
console.log(Employee2.salary);
只读readonly
/****************只读修饰符:属性初始化后不能被修改*********************** */
class Employee3 {
readonly salary: number = 1000;
public name: string;
constructor(name: string,salary:number) {
this.name = name;
this.salary = salary;//readonly修饰的属性只能在构造函数中进行修改
}
public setSlary(s: number) {
this.salary = s; //无法为“salary”赋值,因为它是只读属性。ts(2540)
}
}
类型断言
//类型断言
let n1: any = 100;
let n2 = n1;
console.log(typeof n2); //number.类型有any变成number
//ts中提供了二种类型断言的语法
//1、<>语法
let n3: any = 100;
let n4 = <number>n3; //告诉编译器n4的类型是number
//2、关键字as断言
let n5 = n3 as number; //告诉编译器n4的类型是number
断言的使用
//fn函数在调用的时候,传入的参数可能是数字也可能是字符串
function fn(v: string | number): void {
if (typeof v === "number") {
let v1: number = v as number;
console.log(v1 ** 2); //平方
} else {
console.log((v as string).toLowerCase());
}
}
fn(5);
枚举
enum类型是对JavaScript标准数据类型的一个补充
//枚举定义:enum 枚举名称 {成员1,成员2,成员3}
enum color {
red,
green,
blue,
}
//默认情况下,从0开始为元素编号。 你也可以手动的指定成员的数值
console.log(color.red); //0,获取到的是下标
//通过成员0转换成枚举值
console.log(color[0]); //red,通过下标获取到的是枚举值,类型是字符串
let c1: color = color.red;
let c2: color = color[0]; //不能将类型“string”分配给类型“color”。ts(2322)
let c3: string = color[0]; //字符串类型
//能不能修改枚举类型值
color.green = 5; //无法为“green”赋值,因为它是只读属性。ts(2540)
//具体使用场景:使用枚举,可以限定使用的数据
enum Day {
Sunday,
Monday,
Tuesday,
Wednesday,
Thursday,
Frisday,
Saturday,
}
function fn(): Day {
let n = new Date().getDay();
console.log(Day[n]);
return n;
}
//也可以手动的指定成员的数值
enum Color2 {
Red = 1,
Green,
Blue,
}
let c4: Color2 = Color2.Green;
console.log(c4);
//枚举可以是小数
enum Color5 {
Red = 1.6,
Green,
Blue,
}
let c5 = Color5.Green;
console.log(c5); //2.6 步长值+1
元组
数组合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象
var lists: number[] = [1, 2, 3];
//数组泛型 不允许有其它的类型
var lists2: Array<string> = ["a", "b", "c"];
var lists3: Array<string | number> = ["a", "b", 1, 2];
//任意值
var lists4: any[] = ["a", 1, true];
//元组的声明:使用[]来定义元组类型
let tuple: [number, string] = [1, "jack"];
console.log(typeof tuple); //object,
let tuple2: [number, number[]] = [1, [2, 3, 4]];
interface IPerson {
id: number;
name: string;
}
/*************通过定义方式来区别是元组还是数组************************* */
let tuple3: [IPerson] = [{ id: 1, name: "jack" }]; //元组
let tuple4: IPerson[] = [{ id: 1, name: "jack" }]; //数组定义
let tuple5: [IPerson, Boolean, number[]] = [
{ id: 1, name: "jack" },
true,
[1, 2, 3],
];
//返回元组
function fn(x: number, y: string): [number, string] {
return [x, y];
}
let tuple6 = fn(1, "2");
console.log(tuple6[0]);
类型别名
//type 类型别名,为类型起的新名字
type abc = string;
let s: abc = "hello"; //===let s:string = 'hello'
//可以简写一些类型
type xyz = string | number | boolean;
let n1: string | number | boolean = "1";
let n2: xyz = "2"; //使用的时候更简单
//type和interface的区别?
//interface同一个类型,属性会合并,type不行
interface IPerson {
id: number;
}
interface IPerson {
name: string;
}
let p: IPerson = {
id: 1,
name: "jack",
};