一.简介
TypeScript是JavaScript的超集,增加了数据类型, 帮助JS检查错误, 防止在大型项目中JS出现解释错误.
TypeScript最后还是会编译成JS.
二. 类型
2.1 基本类型
let message: string = 'hello world 1';
let b: boolean = true;
let str: string | null | undefined = "|为联合语法"
//数组
let arr1: Array<number> = [10, 20 ,30]
let arr2: number[] = [2, 3, 4]
let arr3: Array<number | string> = [666, "真的666"]
//参数展开运算符
let arr5: number[] = [1, 2, 3]
let arr6: number[] = [4, 5]
arr5.push(...arr6)
console.log(arr5)//[LOG]: [1, 2, 3, 4, 5]
//元组
let tuple: [number, string] = [666, "这是元组"]
console.log(message, b, str, arr1, arr2, arr3, tuple);
//函数
let add = (x: number, y: number):number => x + y
console.log("合为"+add(1, 2))
//对象
let obj0: Object;
let obj: {x: number, y: number} = {x: 1, y: 2}
console.log("obj的值为" + obj.y)
//symbol 全局唯一引用
//symbol 类型表示一个独一无二的标识符。每个通过 Symbol 函数创建的 symbol 都是唯一的,即使它们的描述相同。
let s1: symbol = Symbol()
let s2 = Symbol()
// 创建一个唯一的 symbol
const mySymbol: symbol = Symbol("mySymbol");
// 创建另一个唯一的 symbol
const anotherSymbol: symbol = Symbol("mySymbol");
// 由于每个 symbol 都是唯一的,这两个 symbol 不相等
console.log(mySymbol === anotherSymbol); // 输出: false
//undefined
let un: undefined = undefined;
let nu: null = null;
//message = null; //报错,因为启动了strictNullChecks(严格null校验)
//void
let noReturn = () => {}//let noReturn: () => void
//any, 变量的默认类型为any
let aaany //let aaany: any
//nerver
let error = () => {//let error: () => never
throw new Error("error")
}
let endless = () => {//let endless: () => never
while(true) {
}
}
2.2 自定义类型
//let 可变参数
let aString = "hello"
aString = "world"
//const 不可变参数
const bString = "666"
bString = "777"//报错
//使用let来实现const, 将cString的类型定义为一个'can not changed string'这样一个特殊类型
//等号前后要保持一致,否则会报错
let cString: 'can not changed string' = "can not changed string"
cString = "yes"//报错
//使用特殊类型
function printText(text: string, aligment: "left" | "right" | "center") {
console.log(text + "---" + aligment)
}
printText("label", "center")//[LOG]: "label---center"
三. 枚举
//数字枚举
enum Season {
Spring,
Summer,
Fall,
Winter
}
console.log(Season.Spring)//0
console.log(Season.Fall)//2
//枚举的原理
//转化为JS
/*
"use strict";
var Season;
(function (Season) {
Season[Season["Spring"] = 0] = "Spring";
Season[Season["Summer"] = 1] = "Summer";
Season[Season["Fall"] = 2] = "Fall";
Season[Season["Winter"] = 3] = "Winter";
})(Season || (Season = {}));
console.log(Season.Spring); //0
console.log(Season.Fall); //2
*/
//字符串枚举
enum Message {
Successs = "成功",
Fail = "失败"
}
/*
var Message;
(function (Message) {
Message["Successs"] = "\u6210\u529F";
Message["Fail"] = "\u5931\u8D25";
})(Message || (Message = {}));
*/
//异构枚举
enum Anser{
N,
Y = "YES"
}
/*
var Anser;
(function (Anser) {
Anser[Anser["N"] = 0] = "N";
Anser["Y"] = "YES";
})(Anser || (Anser = {}));
*/
//枚举成员
enum Char {
//const类型, 编译时确定值
a, //未定义
b = Char.a, //对其他枚举的引用
c = 1 + 3, //常量
//computed类型, 运行时计算确定值
d = Math.random(),
e = "123".length
}
/*
var Char;
(function (Char) {
//const类型, 编译时确定值
Char[Char["a"] = 0] = "a";
Char[Char["b"] = 0] = "b";
Char[Char["c"] = 4] = "c";
//computed类型, 运行时计算确定值
Char[Char["d"] = Math.random()] = "d";
Char[Char["e"] = "123".length] = "e";
})(Char || (Char = {}));
*/
//常量枚举, 使用const声明; 不会被编译进代码, 相当于预编译的宏替换
const enum Month {
Jan,
Fri,
Mar
}
//枚举类型
enum E {a, b}
enum F {a = 1, b = 2}
enum G {a = "hhh", b = "666"}
//let le: E = 3 //Type '3' is not assignable to type 'E'.
//let lf: F = 3 //Type '3' is not assignable to type 'F'.
let lg: G.a = G.a
四.类型接口
4.1 对象类型接口
interface list {
readonly id: number, //readonly, 只读属性
name: string,
age?: number //?可选参数
}
interface list1 {
readonly id: number, //readonly, 只读属性
name: string,
age?: number //?可选参数
}
//interface也可以继承
interface list2 extends list, list1{
}
interface StringArray {
[index: number]:string
}
let chars: StringArray = ["A", "B", "C"]
console.log(chars[2])//C
interface Names {
[x: string]:string | undefined,
[index: number]:string
}
let names: Names = {
0: "A",
1: "B",
"2": "C",
"Wow": "真的6啊"
}
console.log(names[1], names["Wow"])//"B", "真的6啊"
4.2 函数类型接口
//普通函数变量, 不能被继承
let add0: (x: number, y: number) => number; //add0是一个函数类型的变量
add0 = function(x, y) { //给变量复制真正的函数体
return x + y
}
console.log(add0(1, 2))// 3
//函数类型接口
interface Add1 {
(x: number, y: number): number
}
let add1: Add1 = function (x, y){
return x + y
}
console.log(add1(1, 5))//6
// 搞个别名
type Add2 = (x: number, y: number) => number
let add2: Add2 = (x, y) => x + y
console.log(add2(1, 9))//10
//可选参数, z可以不传, 且必须位于必选参数之后
function add5(x: number, y: number, defaultValue=6, z?: number) {
return z ? x + y + defaultValue + z : x + y + defaultValue;
}
console.log(add5(1, 2), add5(1, 2, 3))//[LOG]: 9, 6
五.类
//抽象类, 不能被实例化, 只能被继承
abstract class Animal {
eat() {
console.log("eat")
}
}
class Dog extends Animal{
name: string
static food: string = "骨头"//类成员,使用类名调用
constructor(name: string) {
super()
this.name = name
}
run() {
}
}
console.log(Dog.prototype)
let d = new Dog("汪汪汪")
d.eat();
console.log(d, d.name)
/*
[LOG]: Dog: {
"name": "汪汪汪"
}, "汪汪汪"
*/
//哈士奇继承自Dog
class Husky extends Dog {
color: string
constructor(name: string, color: string) {
super(name)
this.color = color
}
}
//哈士奇继承自Dog-> 给参数增加public属性,可以不用在类里面定义color: string了
class Husky1 extends Dog {
constructor(name: string, public color: string) {
super(name)
this.color = color
}
}
//private 也可以使用#变量来实现private
//protect
// public
六.类型断言
- 使用
as
或者<>
来类型断言 - 类型断言会在运行时被删除
const m1 = document.getElementById("main") as HTMLCanvasElement
const m2 = <HTMLCanvasElement>document.getElementById("main")
七.类型缩小
7.1 使用typeof
来实现类型守卫
let s: string | number = "astring"
// s = 666
if (typeof s === "string") {
console.log("字符串")
} else if (typeof s === "number") {
console.log("数字")
}
let ret: typeof s
ret = "0.0"
7.2 真值缩小
function havePeople(count: number | string | null | undefined) {
if (count) {
console.log("有人")
} else {
console.log("没人")
}
}
//针对number 非0即为true
havePeople(-1) //[LOG]: "有人"
havePeople(0) //[LOG]: "没人"
havePeople(1) //[LOG]: "有人"
//针对string 非空字符串为true
havePeople("") //[LOG]: "没人"
havePeople("h") //[LOG]: "有人"
//null和undefined都为false
havePeople(null) //[LOG]: "没人"
havePeople(undefined) //[LOG]: "没人"
//或者使用一下方法 大写Boolean或者!!, !!其实就是取反再取反
console.log(Boolean("")) //false
console.log(Boolean("h")) //true
console.log(!!0) //false
console.log(!!1) //true
7.3 等值缩小
使用== === != !===
来实现
在 TypeScript 中,== 和 === 是用于比较值的操作符,它们的行为与 JavaScript 中的相同。
- == 是松散相等性比较,也称为“不严格相等”。在比较时,会进行类型转换,尝试使两侧的值类型相同,然后再进行比较。
- === 是严格相等性比较,也称为“严格相等”。它不进行类型转换,只有在类型和值都相同时才被认为相等。
let a: number = 5
let b: string = "5"
// 使用 ==
console.log(a == b); // 输出: true,因为在比较时会进行类型转换
// 使用 ===
console.log(a === b); // 输出: false,因为严格相等要求类型和值都相同
let n1 = 5
let n2 = 6
console.log(n1 == n2)//false
console.log(n1 === n2)//false
7.4 in
在 TypeScript 中,in 关键字主要用于检查对象是否包含某个属性。它可以用于两个场景:
- 检查对象是否包含某个属性
let myObject = { key1: 'value1', key2: 'value2' };
if ('key1' in myObject) {
console.log('myObject has key1 property');
} else {
console.log('myObject does not have key1 property');
}
- 遍历对象的属性
let myObject = { key1: 'value1', key2: 'value2' };
for (let key in myObject) {
console.log(`Property: ${key}, Value: ${myObject[key]}`);
}
//[LOG]: "Property: key1, Value: value1"
//[LOG]: "Property: key2, Value: value2"
八. 函数
8.1 调用签名
可以给函数绑定一个属性
type DescriptionFuntion = {
description: string
(arg: number): boolean
}
function doSomething(fn: DescriptionFuntion) {
console.log(fn.description + " return" + fn(6))
}
function fn(n: number) {
console.log(n)
return true
}
fn.description = "调用签名"
doSomething(fn)
//[LOG]: 6
//[LOG]: "调用签名return true"
8.2 构造签名
- 快速生成类
- 一般需要结合泛型更好使
参考:https://blog.csdn.net/yangxinxiang84/article/details/119490185
class Cls {
name: string
constructor(name: string) {
this.name = name
}
}
//方法1 字面量方式构造签名
function fn0(cls: new(name: string) => Cls): Cls {
return new cls("aaa")
}
const cls0: Cls = fn0(Cls)
console.log(cls0)
function fnt<T>(cls: new(name: string) => T): T {
return new cls("ttt")
}
const clst: Cls = fnt(Cls)
console.log(clst)
//方法2 接口对象字面量方式构造签名
function fn1(cls: {new (name: string): Cls}, name: string): Cls {
return new cls(name)
}
const cls1: Cls = fn1(Cls, "bbb")
console.log(cls1)
//方法3 使用type或者interface
type ClsConstrutor = {
new (name: string):Cls
}
function fn2(cls: ClsConstrutor): Cls {
return new cls("ccc")
}
九.泛型
9.1 类型限制
//泛型T必须要有一个length属性
function longest<T extends {length: number}> (a: T, b: T) {
return a.length > b.length ? a : b
}
9.2 指定类型参数
function combine<T>(arr1: T[], arr2: T[]): T[] {
return arr1.concat(arr2)
}
combine([1, 2, 3], [4, 5, 6])
// 报错了, 因为类型推断为number[]
// combine([1, 2, 3], ["a", "b", "c"])
// 如果你非得乱搞,那需要这样做, 声明数组的类型
let arr = combine<number | string> ([1, 2, 3], ["a", "b", "c"])
console.log(arr)//[LOG]: [1, 2, 3, "a", "b", "c"]
9.3 泛型约束
interface haveLength {
length: number
}
// 传入的参数需要有length属性
function use<T extends haveLength>(args: T) {
console.log(args.length)
}
use("123")//[LOG]: 3
9.4 泛型约束中使用类型参数
function getProperties<Type, Key extends keyof Type>(t: Type, k: Key) {
return t[k]
}
let obj = {
a: 1,
b: 2
}
let ret1 = getProperties(obj, "a")
console.log(ret1)//[LOG]: 1
//let ret2 = getProperties(obj, "c")//报错, 没有这个key
十. This关键字
this的指向问题
在 TypeScript 中,你可以在函数参数中使用 this 参数,这允许你显式地指定函数的调用方。通常,在函数内部,this 关键字用于引用当前对象,但对于一些情况,尤其是在回调函数或异步代码中,JavaScript 的默认行为可能导致 this 的值不是你期望的对象。this和箭头函数, 注意:this在冒号前面.如果this在冒号后面,this就是指向调用方
class MyClass {
name = "MyClass"
getName() {
return this.name
}
getConstName = () => {
return this.name
}
getThisName(this: MyClass) {
return this.name
}
}
//没问题
let cls = new MyClass()
console.log(cls.getName())//[LOG]: "MyClass"
//换个方式就有问题了
//getName获取到的是cls1的, 而不是MyClass的
let cls1 = {
name: "cls1Name",
getName: cls.getName//这是一个方法
}
console.log(cls1.getName())//[LOG]: "cls1Name"
//怎么强行输出MyClass呢.
//1.使用=>, 把方法改成函数
let cls2 = {
name: "cls2Name",
getName: cls.getConstName//这是一个方法
}
console.log(cls2.getName())//[LOG]: "MyClass"
//2.使用this关键字
let cls3 = {
name: "cls3Name",
getName: cls.getThisName
}
console.log(cls3.getName())//报错, 直接不让cls3使用自己的name,只能使用MyClss的name
F
- type和interface的区别
基本相同, 但是interface更容易扩展
//type后面跟个=
type Cls0 = {
a: number
}
let a0: Cls0 = {a: 10}
//使用&符号type增加扩展
type Cls1 = Cls0 & {
b: number
}
let a1: Cls1 = {a: 10, b: 20}
console.log(a1)
//interface后面没有=
interface Bill{
a: number
}
let b0: Bill = {a: 10}
// 使用extend增加扩展
interface Bill1 extends Bill {
b: number
}
let b1: Bill1 = {a: 10, b: 20}
console.log(b1)
//使用extend给type增加扩展 0.0
interface Cls2 extends Cls0 {
c: number
}
let c: Cls2 = {a: 10, c: 30}
console.log(c)
//interface可以多地方声明. type多地方声明则会报错
interface Win {
a: string
}
interface Win {
b: number
}
const w: Win = {
a: "this is a stirng",
b: 666
}
console.log(w)