npm i typescript -g
tsc -v
查看版本号
tsc --init
初始化ts,生成tsconfig.json
tsc -w
编译出一个js文件、
node index.js
node调试js文件
NaN、Infinity也算number类型
还有一些进制也算 比如hex
void类型是null/undefined,一般用于函数
严格模式void不能被赋为null
严格模式在cfg里面"strict"里改
非严格模式下,undefined和null可以穿插赋值
npm i ts-node -g
配置镜像库:
npm i xmzs -g
其他命令
mmp ls
mmp -h
mmp use
生成package.json
npm init -y
生成配置文件node_modules
npm i @types/node -D
然后就可以直接使用 ts-node index.ts
来看到输出了
unknown 只能赋值给自身或者any
unknown 不能用.读到属性
和any差不多
引用数据类型
相当于new Object
但是赋值后无法修改
[propName:string]:any
?
标志属性非必填interface Fn {
(name: string): number[];
}
const a: Fn = function fn(name: string) {
return [1];
};
number[] = Array
number[][] = Array
对象数组用interface
interface x {
name: string;
}
const arr: x[] = [{ name: "qwq" }];
interface Obj {
user: number[];
add(this: Obj, num: number): void;
}
const obj: Obj = {
user: [1, 2, 3],
add(num) {
this.user.push(num);
},
};
obj.add(4)
console.log(obj);
let user: number[] = [1, 2, 3];
//传number类型数组 添加
function findNum(add: number[]): number[];
//传id,单个查询
function findNum(id: number): number[];
//没有传,查全部
function findNum(): number[];
//实现
function findNum(ids?: number | number[]): number[] {
//判断类型是否为数组用Array的方法
if (Array.isArray(ids)) {
user.push(...ids);
return user;
}
//判断是否为number这类用typeof
else if (typeof ids == "number") {
return user.filter((v) => v == ids);
}
//最后也要有返回值
else {
return user;
}
}
findNum([4]);
console.log("查全部", findNum());
console.log("查单个", findNum(1));
| 联合
!!强转
& 交叉(将两个类型合起来)
类型断言:
(type as A)或者(type)
注意:断言只能欺骗一下ts编译器,实际传数据传的啥类型还是啥类型
第7节的代码雨还是很有意思的
https://www.bilibili.com/video/BV1wR4y1377K?p=8&vd_source=133a4c6b8765759be3947374e6336df7
Number Date RegExp Error XMLHttprequest
let num: Number = new Number(1);
有点多,先留个坑后面再整理
和java/c++里学的类实现差不多
教程用例比较复杂,可以理解为在手写vue源码的一部分,虚拟dom渲染为真实dom
基本用法
extends:继承
implements:使用implements来实现一些类共有方法属性的提取,interface提取,implements实现
修饰符
readonly
public
private 只能内部
protected 给子类和内部
在外面都是不能用.访问到的
super调父类方法
实质为父类的prototype.constructor.call
static
静态方法只能被类本身调用,实例无法调用
在static方法里的this也只能访问带static的东西。
原因:
static属性加载在其他属性之前,static初始化的时候别的属性还不存在,调用不了
getter setter
用get和set关键字
存取器要求你将编译器设置为输出ECMAScript 5或更高。 不支持降级到ECMAScript 3。
抽象类abstract
猫狗动物的例子挺好的hh
抽象方法只能描述不能实现
抽象类不能被实例化
类可以当作接口使用
类定义会创建两个东西:类的实例类型和一个构造函数。 因为类可以创建出类型,所以你能够在允许使用接口的地方使用类。
自己写的一个很屑的案例
abstract class Animal {
type: string;
constructor(type: string) {
this.type = type;
}
abstract speak(): void;
}
class Cat extends Animal {
constructor(name: string) {
super("Cat");
this.name = name;
}
name: string;
speak(): void {
console.log(`${this.type} + ${this.name}`);
}
}
let c = new Cat("qwq");
c.speak();
不要整出例如这样的代码就可以了
//不能实例化
let d = new Animal()
//不能实现
abstract speak(): void{
console.log(this.type);
}
const arr: [x: string, y: number] = ["123", 123];
越界后会推断为联合类型
arr.push(1234) 对
arr.push(true) 错
可用readonly修饰(const不能让元组只读)
可用?
使用typeof获取元组的类型
type first = typeof arr[0]
略显奇怪的用法
type first = typeof arr["length"]
可以得到元组的大小为2
实例:用于描述excel数据
enum关键字
可用可不用,相当于是一个对象
enum Color {
//默认从0开始
red = 1,
//为2
blue,
white = 6,
}
console.log(Color.blue);
必须都初始化一下
混着写是可以的
不知道有什么用
enum Color {
red = "qwq",
blue = 1,
}
interface A {
red: Color.red;
}
let obj: A = {
red: Color.red,
};
不知道有什么用
直接编译为常量
const enum Color {
red,
blue,
}
let code: number = 0;
if (code === Color.red) {
console.log("yes");
}
编译为js
var code = 0;
if (code === 0 /* Color.red */) {
console.log("yes");
}
不加const的编译:对象形式
var Color;
(function (Color) {
Color[Color["red"] = 0] = "red";
Color[Color["blue"] = 1] = "blue";
})(Color || (Color = {}));
var code = 0;
if (code === Color.red) {
console.log("yes");
}
字符串不可以用这玩意
可以互相取挺方便的,value拿key就用这招
enum Color {
red,
blue,
}
let code: number = Color.red;
let key = Color[code];
console.log(code);//0
console.log(key);//red
不写:的情况下,会自动推断变量的类型,默认any
type关键字
type-interface
type不能用extends,可以使用&,|来定义交叉、联合类型
type重名不会合并
type num = 1 extends never ? 1: 0
num为0,extends:包含
左边的值会作为右边类型的子类型
type a = number & string
a为never类型
然后对于函数,死函数/运行报错函数设置为never类型
function a():never{
while(true){
}
}
never处于类型的最底级,联合没用
一般用于switch语句中default的部分,通过never类型的错误找到逻辑错误
唯一标识,在不同的内存空间
let a1: symbol = Symbol(1);
let a2: symbol = Symbol(1);
console.log(a1 == a2);//false
Symbol.for
for全局symbol是否注册过这个key,有就用,无才创建。但是需要传字符串值
let a1: symbol = Symbol.for("1");
let a2: symbol = Symbol.for("1");
console.log(a1 == a2);//true
用处:解决属性的key取重复的问题
因为对symbol而言,就算里面的值是一样的,也算不同的
let a1: symbol = Symbol(1);
let a2: symbol = Symbol(1);
let obj = {
[a1]: 123,
[a2]: 234,
//name: "qwq",
//name: "sayori",
//报错:对象文本不能具有多个名称相同的属性,在js中会下面的覆盖上面的
};
console.log(obj);
//{ [Symbol(1)]: 123, [Symbol(1)]: 234 }
问题:
for in 、Object.keys 、Object.getOwnPropertyNames都不能读到symbol
需要使用
Object.getOwnPropertySymbols,但是这个只能单独取symbol
使用Reflect.ownKeys才可以都取到
function* gen() {
//同步/异步都可以
yield Promise.resolve("qwq");
yield "123";
yield "sayoriqwq";
}
const A = gen();
console.log(A.next());
console.log(A.next());
console.log(A.next());
console.log(A.next());
输出:
{ value: Promise { 'qwq' }, done: false }
{ value: '123', done: false }
{ value: 'sayoriqwq', done: false }
{ value: undefined, done: true }
done为true说明迭代完成了
和生成器其实差不多,也是一个函数,用法也是一样的
let arr = [1, 2, 3];
console.log(arr[Symbol.iterator]().next().value);//1
set map
学过c++的stl应该对这玩意不陌生
set自带去重
let set: Set<number> = new Set([1, 1, 2, 2]);
console.log(set);//Set(2) { 1, 2 }
map相关方法
let map: Map<any, any> = new Map();
let arr = [1, 2, 3];
map.set(arr, "qwq");
console.log(map.get(arr));//qwq
然后讲了一些伪数组
arguments,querySelectorAll
迭代器应用场景:支持遍历所有这些乱七八糟的数据类型
语法糖 for of
二者等效,也可以用来遍历map、array等
let set: Set<number> = new Set([1, 1, 2, 3]);
const each = (value: any) => {
let It: any = value[Symbol.iterator]();
let next: any = { done: false };
while (!next.done) {
next = It.next();
if (!next.done) {
console.log(next.value);
}
}
};
for(let value of set){
console.log(value);
}
注意:for of对象不能用,对象身上没有iterator
数组解构:底层原理也是调iterator
注意:对象解构不是用的这个
使对象支持for of:手动实现iterator方法
let obj = {
max: 5,
current: 0,
//配置迭代器
[Symbol.iterator]() {
return {
//迭代到下一层之前把属性速记
max: this.max,
current: this.current,
next() {
//迭代完成
if (this.current == this.max) {
return {
value: undefined,
done: true,
};
}
//继续迭代
else {
return {
value: this.current++,
done: false,
};
}
},
};
},
};
for (let value of obj) {
console.log(value);
}
console.log([...obj]);
动态类型
function qwq<T>(a: T, b: T): T[] {
return [a, b];
}
//一样的,一般让ts自己推断类型
console.log(qwq(1, 2));
console.log(qwq<number>(1, 2));
类型泛型:
type A<T> = string | number | T;
let a: A<null> = null;
接口也可以用
相比于any,泛型可以推断类型,而any只能是any
泛型也可以支持多个
function add<T, K>(a: T, b: K): (T | K)[] {
return [a, b];
}
add(1,false)
可以自己写一下代码,就可以看到在写的时候ts对类型的推断了,不传的时候是unknown,传的时候推断为我们传的值的类型
调接口的时候用
https://www.bilibili.com/video/BV1wR4y1377K/?p=17&spm_id_from=pageDriver&vd_source=133a4c6b8765759be3947374e6336df7
控制类型的范围
interface Len {
length: number;
}
function fn<T extends Len>(a: T) {
a: length;
}
fn(111);//错,number类型没有length属性
fn("1q213");
fn([1, 2, 3]);
let obj = {
name: "sayori",
age: 123,
};
//T限制为传引用类型,K限制为传T的key值
function fn<T extends object, K extends keyof T>(obj: T, key: K) {
return obj[key];
}
console.log(fn(obj, "name"));//sayori
console.log(fn(obj, "qwe"));//报错,qwe不是obj里的一个key
而且在写代码的时候也会有一个很智能的提示
目前来说是没看懂是咋实现的,已经有点晕掉了
interface Data {
age: number;
name: string;
sex: string;
}
type Options<T extends object> = {
readonly [key in keyof T]: T[key];
};
type A = Options<Data>
对A来说,就已经实现了Data里每一项都为只读
当然也可以用?修饰使得Data项目都可选,ts还有专门实现了这个功能的方法partial
tsc --init
生成
配置文件里有注释,也可以去翻官方文档
实质是包了一层function
可以嵌套
在最新版本中,推荐使用ES Modules作为模块化的解决方案,而不是过度使用namespace
抽离命名空间
以文件形式export,然后import
简化命名空间
用import newName = A.B.C.D
的形式为命名空间取别名
ts-node现在认识它了
重名算到一起(和interface一样)
从ts2.0开始,三斜线引用被废弃,推荐使用es6模块语法和import语句来替代
主要用于旧版本中
///
还可以用于声明文件
配置也有点麻烦,不学了
你说得对,但是import是es6模块语法,后面忘了
declare
高级的ts语法不会一点,先补一下es6再回来填这个坑
完结撒花(