typescript初学

学习内容:

typescript基础

  1. 基本数据类型
  2. 类型适配(断言)
  3. Interface接口
  4. class类
  5. 访问修饰符
  6. Generics泛型
  7. type 和 interface 异同

学习产出:

安装开发环境轻量级服务器

npm i -S lite-server

修改package.json

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "lite-server" // 加入启动命令
  },

启动项目,localhost:3000

npm start

ts的基础类型:string,number, boolean

ts中使用最频繁的类型就是字符、数字和布尔值。有一点要注意,这几个类型表述都是小写,千万不要跟 js当中的String, Number, Boolean混淆。

数组

常见的数组类型表达T[]和Array。

比如:
[1,2,3,4]一个数字集合的数组类型,我们可以用number[]及Array这样的语法来表示。

记住一点[number] 可不是数组类型,它是一个标准的 Tuples(元组)。

let list1: number[] = [1,2,3,4];
let list2: Array<number> = [1,2,3,4];
let list3 = [1,2,3,4];
let list4 = [1, "a"]; // 只能存放string,number
let list5:any[] = [1, "a", true]; // 可以存放任意类型

元组 Tupple

固定长度、固定类型的数组
声明时必须指定类型,否则就是一个联合类型的数组,不是元组
let tup1: [number, string] = [1, "a"];
console.log(tup1);
tup1[0] = 2;
tup1[1] = "b";
tup1.push(1); // 元组的bug
console.log(tup1);

联合(Union)类型

指定类型
 let union1: string | number | string[];
 union1 = 1;
 union1 = "a";
 // union1 = [1,3]; // 编译报错
指定取值范围
 let union2: 1 | 2 | false;
 union2 = 1;
 union2 = false;

字面量(Literal)类型

let lite1: 1 | "a" | true | [1, 3];

在变量声明的同时指定其类型

定义方式——变量:类型

let myName: string = "Alice";

ts有个特性:类型推断。如上例子也可以直接:

let myName = "Alice";

ts也会根据赋值类型,推断出来变量的类型。

关于标量是否需要指定其类型,官方说:在定义变量的时候,尽可能的少指定其类型。

枚举类型(Enum)

 enum Color {
 	red = "a",
 	blue = 3,
 	yellow = "2"
 }
 let color1 = Color.red;
 let color2 = Color.blue;
 let color3 = Color.yellow;
 console.log(color1, color2, color3);

枚举是TypeScript为数不多的特性之一,它不是JavaScript的类型级扩展。

1. Numeric enums(数值枚举)
enum Direction {
  Up = 1,
  Down,
  Left,
  Right,
}

enum Direction {
  Up,
  Down,
  Left,
  Right,
}

数值枚举,默认的起始数值是1,后续以此递增。如果指定了头部值,那么默认值就会变成指定值。

2. String enums(字符枚举)
enum Direction {
  Up = "UP",
  Down = "DOWN",
  Left = "LEFT",
  Right = "RIGHT",
}

枚举常用在字面化表达一个变量的不同类型值,比如:性别。

any动态类型

如果设置了某个变量的类型为any类型,那么不单单是这个变量本身类型不会被检测,它的属性和方法也会绕过ts的类型检测。

let rand:any = 1;
rand = true;
rand = {};
// rand(); // 编译通过,执行js才报错

unknown

let rand2:unknown = 1;
// rand2(); // 编译报错
if(typeof rand2 === "function")
 rand2();

void 变量本身就不存在,undefined变量未赋值

never 永远没有返回值

一般用来处理异常
function throwError(message: string, errorCode: number): never {
	throw{
		message,
		errorCode
	}
}
throwError("not found", 404);

类型适配(类型断言)Type Assertions

let message: any;
message = "abc";
message.endsWith("c"); // 编辑器无提示

// 两种方式
let re1 = (<string>message).endsWith("c");
let re2 = (message as string).endsWith("c");
ts的非undefinednull的断言修饰符“!”)

TypeScript还有一种特殊语法,用于在不进行任何显式检查的情况下从类型中删除null和undefined。具体实例如下:

function liveDangerously(x?: number | null) {
  console.log(x.toFixed()); 
  //Object is possibly 'null' or 'undefined'
  console.log(x!.toFixed());
}

函数类型

可选参数和默认值只能放在最后一个
// code: number = 1
let log = (message: string, code?: number): string => {
	return `${message}${code}!!`;
}
log("雷猴");

object对象类型

js中是key to value 键值对

ts中是key to type 键类型对

将所有的对象属性一一列出就是对象类型的基础用法。
参数可选:

function printCoord(pt: { x: number; y?: number }) {
  console.log("The coordinate's x value is " + pt.x);
  console.log("The coordinate's y value is " + pt.y);
}
printCoord({ x: 3, y: 7 });

Interface接口

let drawPoint = (point: Point) => {
	const { x, y } = point;
	console.log(x, y);
}
drawPoint({x:100, y:120});
// drawPoint({x:"a", y:"b"});// 编译报错

interface Point {
	x: number,
	y: number
}

Class类

以下代码中getX和setX使用getter setter懒人包示范,编译时报错Accessors are only available when targeting ECMAScript 5 and higher. 使用命令tsc -t es5 demo.js指定js版本即可。

// IPoint 表示一个Interface
interface IPoint {
	// class类中使用private修饰的变量,在接口中应该去掉
	// x: number;
	// y: number;
	drawPoint: ()=>void;
	getDistances: (p: IPoint) => number;
	X: number; // getter setter懒人包
	// getX: () => number;
	// setX: (value) => void;
	getY: () => number;
	setY: (value) => void;
}

接口实现使用关键词implements

class类中要实现IPoint中所有函数

js不可重载,有且仅有一个 constructor,可选参数和设置参数默认值可以变相达到重载效果

y?: number 表示可选参数

访问修饰符public(默认), private, protected,在声明构造函数的同时顺便完成成员变量的声明

class Point implements IPoint {
	// 成员变量
	// x: number;
	// y: number;
	constructor(private x: number, private y: number) {
		// this.x = x;
		// this.y = y;
	}
	// 成员函数
	drawPoint = () => {
		console.log("x: ", this.x, ", y: ", this.y);
	};
	getDistances = (p: IPoint) => {
		return Math.pow(p.X-this.x, 2) + Math.pow(p.getY()-this.y, 2);
	};
	// 缓冲带,避免一些非法输入
	set X(value: number) {
		if(value < 0) {
			throw new Error("value不能小于0");
		}
		this.x = value;
	};
	get X() {
		return this.x;
	};
	setY = (value: number) => {
		if(value < 0) {
			throw new Error("value不能小于0");
		}
		this.y = value;
	};
	getY = () => {
		return this.y;
	};
}
const point = new Point(3, 4);
// point.x = 2;// Property 'x' is private and only accessible within class 'Point'.
// point.y = 3;
// point.setX(-19);
// point.setX(19);
// console.log(point.getX());
point.X = 18;
console.log("point.X=", point.X); // 18
point.drawPoint();

Generics 泛型

其中输入的类型与输出的类型相关,或者两个输入的类型以某种方式相关。

let lastInArray = <T>(arr:T[]) => {
	return arr[arr.length-1];
}

// 鼠标放在下列const声明的变量上可以看到变量的类型
const l1 = lastInArray([1, 2, 4]); // number
const l2 = lastInArray(["a", "b", "c"]); //string
const l3 = lastInArray<string | number>([1, "a", "b"]); // string | number

// 指定默认类型
let makeTuple = <T, Y = number>(x: T, y: Y) => [x, y];
// 可以指定类型,不指定时js会动态匹配类型
const v1 = makeTuple(1, "a");
const v2 = makeTuple<boolean>(true, 1);

不常用的类型

从ES2020开始,JavaScript中有一个用于非常大整数的原语BigInt:

// Creating a bigint via the BigInt function
const oneHundred: bigint = BigInt(100);
 
// Creating a BigInt via the literal syntax
const anotherHundred: bigint = 100n;

JavaScript中有一个原语,用于通过函数Symbol()创建全局唯一引用:

const firstName = Symbol("name");
const secondName = Symbol("name");
 
if (firstName === secondName) {
This condition will always return 'false' since the types 'typeof firstName' and 'typeof secondName' have no overlap.
  // Can't ever happen
}

Narrowing(类型窄化/过筛)

in操作符

当一个属性为可选字段的时候,用in判断,它会出现在true和false的两边。

type Fish = { swim: () => void };
type Bird = { fly: () => void };
 
function move(animal: Fish | Bird) {
  if ("swim" in animal) {
    return animal.swim();
  }
 
  return animal.fly();
}

type 和 interface:

区别:
  1. 接口 interface 只能用于定义对象类型。
  2. 类型别名 type 可以用来给一个类型起个新名字,当命名基本类型或联合类型等非对象类型时非常有用。
  3. 同名接口会自动合并,而类型别名不会。
相同点:
  1. 类型别名和接口都可以用来描述对象或函数
type Point = {
  x: number;
  y: number;
};

type SetPoint = (x: number, y: number) => void;
interface Point {
  x: number;
  y: number;
}

interface SetPoint {
  (x: number, y: number): void;
}
  1. 类型别名和接口都支持扩展: 类型别名通过 &(交叉运算符)来扩展,而接口通过 extends 的方式来扩展。
// 类型别名扩展

type Animal = {
  name: string
}

type Bear = Animal & { 
  honey: boolean 
}

const bear: Bear = getBear() 
bear.name
bear.honey
// 接口扩展

interface Animal {
  name: string
}

interface Bear extends Animal {
  honey: boolean
}
 // 此外,接口也可以通过 extends 来扩展类型别名定义的类型:

type Animal = {
  name: string
}

interface Bear extends Animal {
  honey: boolean
}
// 同样,类型别名也可以通过 &(交叉运算符)来扩展已定义的接口类型:


interface Animal {
  name: string
}

type Bear = Animal & { 
  honey: boolean 
}
使用场景
  1. 使用类型别名的场景:

定义基本类型的别名
定义元组类型
定义函数类型
定义联合类型
定义映射类型

  1. 使用接口的场景:

需要利用接口自动合并特性时问
定义对象类型且无需使用type时

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值