这是我参与「第五届青训营 」伴学笔记创作活动的第 4 天
为什么选择TS
- TS是静态类型语言,大部分错误可以在编译时检测出来。
- 拥有 IDE 的加强(类型提示等),会通过语法生成文档。
- 兼容 JS 的所有特性,可以与 JS 共存,并且最后编译出来也是 JS。
对于 Interface 与 Type 个人理解
类型使用 type
type 与 interface 大部分功能相同,我认为在需要使用类型时(如声明参数、变量)应使用type,而不是使用interface,原因如下:
interface会合并重复声明。type可以声明基本类型、联合类型、交叉类型、元组。- 使用
type时 IDE 可以查看具体的字段,interface则不行。
Interface 的样子:
Type 的样子:
类使用 interface
在跟类相关时可以使用interface,interface与 C#、Java 基本作用一样。
interface ClockInterface {
currentTime: Date;
setTime(d: Date);
}
class Clock implements ClockInterface {
currentTime: Date;
setTime(d: Date) {
this.currentTime = d;
}
constructor(h: number, m: number) { }
}
Keyof
keyof 类型索引,可以通过它得到所有key组成的字符串字面量。
Infer
infer 可以推导泛型参数。
type ParamType<T> = T extends (arg: infer P) => any ? P : T;
interface User {
name: string;
age: number;
}
type Func = (user: User) => void;
type Param = ParamType<Func>; // Param = User
type AA = ParamType<string>; // string
infer P 表示待推断的函数参数,如果 T 能赋值给 (arg: infer P) => any,则结果是P,否则为 T。
infer 只能在 extends 的右边使用,infer P 的 P 也只能在条件类型为 True 的一边使用。
协变与逆变
以下仅个人理解
协变:子类到父类上
逆变:父类到子类上
举个例子:
class Father {
base = ''
}
class Children extends Father {
type = 'children'
}
// 协变
const f: Father = new Children()
// 父
let funF = (f: Father) => {}
// 子
let funC = (c: Children) => {}
// 逆变
funC = funF
在参数、变量、函数返回值中有不同的规则:
- 参数:只允许发生逆变,也就是子类到父类。
- 变量:只允许发生协变,也就是父类到子类。
- 函数返回值:与变量相同,只允许协变,父类到子类。
举个例子(开启严格函数类型检查):
class Father {
base = ''
}
class Children extends Father {
type = 'children'
}
// 变量协变
const f: Father = new Children()
// 变量逆变(不被允许)
const c: Children = new Father() // Not Work.
// 参数逆变与协变
let funF = (f: Father) => {}
let funC = (c: Children) => {}
// 参数逆变
funC = funF
// 参数协变(不被允许)
funF = funC // Not Work.
// 返回值协变与逆变
let funRF: ()=>Father = (f: Father) => new Father()
let funRC: ()=>Children = (c: Children) => new Children()
// 返回值协变
funRF = funRC
// 参数逆变(不被允许)
funRC = funRF // Not Work.
TS在浏览器与Node环境中的使用
浏览器环境
Webpack/Vite
graph TD
配置Webpack --> 配置tsconfig --> 运行Webpack/Vite --> loader/esbuild处理ts文件并进行编译与检查
Node环境
graph TD
安装ts --> 配置tsconfig --> tsc编译 --> 运行编译的JS文件
可以配置package.json一键运行:
"scripts": {
"run": "tsc <ts入口文件路径> && node <编译后的js入口文件路径>"
}
举个例子: