概念
- JavaScript超级语言,提供了类型系统和ES6支持,有自己的编译工具
- TypeScript操作类型集合,集合有集合的运算;JavaScript操作值,值有值的运算
环境
安装和编译
// index.ts
npm i - g typescript
// 编译
tsc index.ts
工具
typescript-play
type-challenges
实用工具类型
配置
- 创建配置文件
- 设置配置项
- 使用配置文件
配置DOC
基本配置
tsconfig参考说明
tsconfig结构
// 初始化配置文件tsconfig.json
node_modules/.bin/tsc --init --locale zh-CN
tsc --init
// 配置说明
* target: ts代码转换成哪个版本的js代码 es5 es3
* module: 使用的模块化的标准是什么
* outDir: 转换后的js代码存放的文件夹路径
* rootDir: 哪个目录中的ts代码进型转换,ts代码的存放路径
* strict: 转换为严格模式的js代码!
// 使用配置文件
tsc -p ./tsconfig.json
// 可以针对不同场景使用基本配置
https://github.com/tsconfig/bases/
// tsconfig参考说明
https://www.typescriptlang.org/tsconfig
// tsconfig结构
http://json.schemastore.org/tsconfig
声明文件
- 标记某个 js 库里面对象的类型
- 类似Node模块的采用 CommonJS 模块规范 .d.ts
类型系统
结构类型系统:通过类型的结构确定两个类型是否相等(TypeScript,Haskell,Ocaml,Go...)
名义类型系统:通过类型的名称确定两个类型是否相等(C,C++,Java,C#,Rust...)
类型与集合关系/类型联合和交叉
- 空集 ---- never
- 单元素集合 ---- 字面量类型
- 有限集合 ---- 布尔类型
- 无限集合 ---- String/BigInt/Symbol/Number
- 全集 ---- unknown
类型缩小和拓宽:
体现TypeScript在确定性和灵活性上取得平衡 拓宽:let, var typescript将字面量类型拓宽为更宽泛的类型
缩小:某些情况下typescript 将类型推断为更确切的类型
(null check, as const, instanceof, typeof, 属性检查, Tagged Union, 用户类型守卫(User-defined Type Guard), 代码流分析)
type-widening-and-narrowing
字面量类型拓宽
Widening-and-Narrowing-in-Typescript
类型空间与值空间
值空间(运行时的各种类型)
- let, const, var后的符号
- 类型操作
- 函数参数和默认值
- for-in遍历
- if-else判断 类型空间(编译期的各种类型)
- 编译后消失
- 类型别名/类型注解
type T = typeof Person; const p: Person - 断言后的符号
target as/is HTMLELEMENT - 类型操作
- 泛型参数和默认值
- key-in遍历
- 条件类型判断 值空间和类型空间
- enum, class, namespace后的符号
- typeof
值空间:返回字符串'string','number','boolean','object','undefined','function','bigint','symbol'
类型空间:返回标识符类型 - []索引 值空间:val.field或val[field或val]返回值 类型空间:Type[T]
interface Person { name: string, age: number, id: symbol }
type personName = Person['name'] // name是字面量类型,不是字符串
type personNameAge = Person['name' | 'age'] // 也可以是字面量的集合
值空间
// 类型空间
interface myArray<T> {
[name: string]: T,
[age: number]: T,
[id: symbol]: T
}
type nameArray = myArray<string> // 映射类型
- this
Yehuda Katz --- Understanding JavaScript Function Invocation and "this"
值空间:this指向在运行时确定
类型空间:类方法链式调用 - & | 运算符
值空间:位运算与或非
类型空间:交叉和联合 - const
值空间:常量
类型空间:常量断言,收窄类型 - extends
值空间:定义子类
类型空间:类型约束T extends number或接口继承interface A extends B - in
值空间:判断属性是否存在
类型空间:映射类型key的声明
类型定义
Top Type
Undefined<--Void<--Unknown<--Null
Number<--NumberEnum/BigInt/Boolean/String<--String Enum/Symbol<--Unique Symbol/Object<--Function/Constructor/Array<--Turple
Bottom Type
never
Top Type | Bottom Type
any
下层可以赋给上层,unknown可以指向任何类型,不存在never类型的变量
日常类型:
字符串类型string:
type Dir = 'n | 's' | 'w' | 'e';
type Dir = Dir | Capitalize<Dir> | Uppercase<Dir>; // Dir | 'N' | 'S' | 'W' | 'E'
符号类型symbol:
unique symbol必须const才可行 必须通过typeof 常量的形式引用; unique symbol赋值给灵另一个const 拓宽为symbol,不希望拓宽,注解为常量typeof
let a = Symbol('a');
let a1: unique symbol = a; // Error
const b: unique symbol = Symbol('b'); // const才可行 必须通过typeof 常量的形式引用
const b1: typeof b = b; // 不希望拓宽,注解为常量typeof
数字类型number:
number NaN Infinity 浮点数 BigInt与Number转换运算
let a = 1; // number
let b = Infinity; // number
const PI = 1; // PI
let nan = Infinity; // number
let d: 4.56; // 4.56
// bigint -(2^53 - 1), (2^53 - 1
let a = 1234n; // bigint
const hex = BigInt("0x1fffffffffff"); // bigint
let a = a + BigInt(123); 不混合运算,转换运算
布尔类型boolean:
let a = true; // boolean 拓宽
const a = true; // true 收窄
let d: boolean = true; // boolean
let d: true = true; // true
数组类型Array和元祖类型Turple:
const数组不收窄,空数组any[], any[]通过push离开作用域数组确定类型,元组类型支持rest操作符,支持可选操作符
let list: number[] = [1, 2, 3];
let list: Array<number> = [1, 2, 3];
(() => {
let e = [];
e.push(1, 'red');
return e; // (string | number)[]
})();
// 元组
let x: [string, number];
type NBS = [boolean, ...string[]]
对象类型Object:
// 类型注解
const Person: { name: string, age: number } = {
name: '123'
age: 234
}
// 类型别名
type Person = { name: string, age: number }
type personKeys = keyof Person
枚举类型Enum:
未显示赋值的自增性,显示赋值字符串不存在反反向映射,可以合并,常量枚举被替换为对应的值,不会在值空间创建变量,没有双喜那向映射
enum Color {Red = 1, Green = 2, Blue = 4}
let c: Color = Color.Green;
null | undefined | never | void类型:
undefined未定义,null已声明未赋值
void没有显示返回值,never函数无法返回
function error(msg: string): never {
throw new Error(msg)
}
unknown | any类型:
无法预知类型用unknown,收窄类型后使用
避免any,隐藏设计细节,开启严格noImplicityAny
泛型 | 接口 | 类 | 函数 | 条件类型 | 模板字面量类型 | 映射类型 | 类型操作
- 泛型:将两个或多个具有相同类型的值关联起来;创建可重用的组件,一个组件可以支持多种类型的数据;泛型约束
function identity<T>(arg: T): T { return arg; }
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length);
// Now we know it has a .length property, so no more error
return arg;
}
- 接口:结构进行类型检查。 它有时被称做“鸭式辨型法”或“结构性子类型化”,描述函数类型
类型别名更为通用,右侧可包含类型表达式(联合、交叉、条件类型),具有某种结构 接口间可继承,检查二者关系,类型联合最大尝试,不报错 同作用域多个同名接口合并,多个同名类型报错
function printLabel(labelledObj: { label: string }) {
console.log(labelledObj.label);
}
let myObj = { size: 10, label: "Size 10 Object" };
printLabel(myObj);
interface SearchFunc { (source: string, subString: string): boolean; }
- 类:基于类的面向对象的方式,成员:属性、方法、构造函数;继承(extends);公共(public),私有(private),受保护的修饰符(protected),只读(readonly),存取器(get, set),静态属性(static),抽象类型(abstract)
class Greeter {
greeting: string; 、 属性
constructor(message: string) { this.greeting = message; } // 构造函数
greet() { return "Hello, " + this.greeting; } // 方法
}
class AGreeter extends Greeter {} // 继承
let greeter = new Greeter("world");
- 函数:实现抽象层,模拟类,信息隐藏和模块,区别类,命名空间和模块,函数定义行为;重载
this参数是个假的参数,它出现在参数列表的最前面
let myAdd: (x: number, y: number) => number = function(x: number, y: number): number {
return x + y;
};
// `this`参数是个假的参数,它出现在参数列表的最前面
function f(this: void) { // make sure `this` is unusable in this standalone function }
- 映射类型:从旧类型中创建新类型的一种方式,新类型以相同的形式去转换旧类型里每个属性
type Keys = 'option1' | 'option2';
type Flags = { [K in Keys]: boolean };
- 字面量类型
字符串字面量类型还可以用于区分函数重载
数字字面量类型用于缩小范围调试bug
// 字符串字面量类型还可以用于区分函数重载
function createElement(tagName: "img"): HTMLImageElement;
function createElement(tagName: "input"): HTMLInputElement;
// ... more overloads ...
function createElement(tagName: string): Element {
// ... code goes here ...
}
// 数字字面量类型用于缩小范围调试bug
function foo(x: number) {
if (x !== 1 || x !== 2) {
// ~~~~~~~ // Operator '!==' cannot be applied to types '1' and '2'.
}
}
- 类型操作 keyof
keyof 获取类型上已知的、public的类型联合
列举法 如对象类型; 公式法 如映射类型 key-in
type k1 = keyof unknown/undefined/void/null/object/never --> never
type k2 = keyof any ---> string | number | symbol
type k3 = keyof bigint ---> 来自interface BigInt
type k4 = keyof string ---> 来自interface String
type k5 = keyof boolean ---> 来自interface Boolean
type k6 = keyof number ---> 来自interface Number
type k7 = keyof number ---> 来自interface Symbol
JSDoc 代码即注释
作用:注释的形式来降低 JavaScript 项目的维护难度,提升可读性,不会对源码产生任何的影响,是一个过渡方案。
重载签名和实现签名
规则:无法预知类型用unknown,收窄类型后使用
规则:避免any,隐藏设计细节,开启严格noImplicityAny
规则:在可能的情况下,始终更喜欢具有联合类型的参数而不是重载
规则:如果可能,使用类型参数本身而不是约束它
规则:始终使用尽可能少的类型参数
规则:如果一个类型参数只出现在一个位置,强烈重新考虑你是否真的需要它
规则:为回调编写函数类型时,切勿编写可选参数,除非您打算在不传递该参数的情况下调用该函数
规则:请注意,目前无法在解构模式中放置类型注释。这是因为以下语法在 JavaScript 中已经意味着不同的东西。
interface Props {
a?: number;
b?: string;
}
const obj: Props = { a: 5 };
const obj2: Required<Props> = { a: 5 };
// Property 'b' is missing in type '{ a: number; }' but required in type 'Required<Props>'.
参考链接
typescriptlang
typescript-book-chinese
掘金
知乎专栏
# Questions tagged [typescript]
源码issues
git-shortlog
Books
TypeScript编程
深入理解TypeScript
Effective TypeScript
Programming with Types
https://git-scm.com/docs/git-shortlog/zh_HANS-CN
typescript git(:main) git shortlog -sn