any
任何类型都可以赋值给any
。any
也可以给任何类型赋值unknown
任何类型可以赋值给unknown
,但是unknown
类型赋值给其它类型需要对其进行类型缩小。
type
- 类型一般都是大写字母开头
type Fish = {
name: string,
swim: () => void
}
类型谓词
- 返回一个布尔类型
is XXX
type Fish = {
name: string,
swim: () => void
}
type Bird = {
name: string,
fly: () => void
}
type Animal = Fish | Bird;
function run(ani: Animal): ani is Fish {
return (ani as Fish).swim !== undefined;
}
const res1 = run({
name:"jinyu",
swim:()=>{
}
})
const res2 = run({
name:"maque",
fly:()=>{
}
})
console.log(res1,res2); // true false
调用签名
- 可以给函数添加属性
- 不可以给函数定义
name
属性名
type Func = {
fname: string,
(s: string): void
}
function runFun(fn: Func) {
fn('hello world');
}
function testFn(s: string) {
console.log(s);
}
testFn.fname = 'strReturnVoid';
runFun(testFn);
构造签名
- 类型参数是用来关联多个值的类型的。如果一个类型参数在函数签名中只使用一次,那么他是没有必要再次定义的
class Animal {
cname: string
constructor(name: string) {
this.cname = name;
}
}
type classsFunc = {
new(s: string): Animal
}
function runFun(fn: classsFunc, cname: string): Animal {
return new fn(cname);
}
const cat = runFun(Animal, 'cat');
console.log(cat.cname); // cat
可选参数
- ?
- 不能与参数默认值同时使用
function fu1(n?:number){
return n;
}
function fn2(n:numbner = 12.548){
return n.toFixed(2);
}
- 当为回调写一个函数类型时,永远不要写一个可选参数,除非你打算在不传递该参数的情况下调用函数。
函数重载
- 必须得有一个实现函数
- 这个实现函数包括全部函数重载的参数,并且返回值与其他函数返回值相同
function makeDate(timestap: number): Date;
function makeDate(m: number, d: number, y: number): Date;
function makeDate(mOrTimestap: number, d?: number, y?: number): Date {
if (d !== undefined && y !== undefined) {
return new Date(mOrTimestap, y, d);
} else {
return new Date(mOrTimestap);
}
}
const date1 = makeDate(1236546544);
const date2 = makeDate(2022, 4, 1);
console.log(date1,date2);
重载签名和实现签名出错原因
- 参数不正确
- 参数类型不正确
- 返回类型不正确
- 我们只能看到重载函数的参数约束,无法看到实现函数的参数约束
如何编写好的重载函数
- 在可能的情况下, 总是倾向于使用联合类型的参数而不是重载参数
this
可以直接用作函数的参数,但是不建议这么做
函数的其他类型
void
函数无返回值object
任何的不是基元的值 (string numbner bigint boolean symbol null undefined)- 不同于{} 不同于Object
- object 不是 Object 。在 ts 中始终使用 object
unknown
类型代表任何值。这与any类型类似,但更安全,因为对未知的unknown值做任何操作都是不合法的- unknown 类型的值赋值给其他类型的值的时候,需要对其进行类型缩小才可以进行赋值,其他类型的值都可以赋值给 unknown
never
永远不会被观察到的值- 抛出异常
- 函数终止
- 死循环
Function
- 全局性的Function类型描述了诸如bind、call、apply和其他存在于Javascript中所有函数值的属性。
- Function 类型的值总是可以被调用,这些调用返回any
参数展开运算符
- 形参展开 …
- 实参展开 …
const args = [8,5] as const;
const angle = Math.atan2(...args);
参数解构
- const {a,b} = {a:1,b:2}
返回void 类型
- 一个返回
void
类型的函数,可以返回任意类型,但是返回的数据会被忽略 - 当一个字面的形式定义的函数返回
void
类型的时候,该函数必须不返回任何东西
type Fun = () => void
对象类型
-
type interface
-
属性修改器
- ?:可选属性
- readonly age:number 只读属性
- (对基本类型起作用,复杂数据类型只是对地址进行了固定)
- 可以通过 再次定义readonly 的方式对其进行再次只读
- 在对象给对象赋值的时候,ts不考虑该对象的属性是否是只读属性。readonly的属性可以通过别名改变
- 索引签名
- 索引签名和只读属性可以使数组中的数据不被改变
- 扩展类型
- extends
- 可继承多个定义的接口。之间用逗号隔开
- ***两个同名 interface 会自动进行合并,两个同名type会出现同名错误 ***
- 默认值
-
解构的时候最好不要在对象中使用类型,它与es6的别名方法冲突
交叉类型
- type TypeArr = 类型1 & 类型2
泛型对象类型
type Box<T> = {
content: T
}
type OrNull<T> = T | null; // 可以是 T 类型或者为 null
type OneOrMany<T> = T | T[]; // 可以是 T 类型,或者是T类型的数组
type OneOrManyOrNull<T> = OneOrMany<OrNull<T>> // 可以是 T 类型、null类型、T类型的数组。
泛型函数
- 泛型函数的限制条件 extends { length:number }
- 使用受限值
- 指定类型参数 <number|string>
- 防止 ts 自动类型推断
- 编写优秀通用函数的准则
- 可能的情况下,使用类型参数本身,而不是对其进行约束
- 尽可能少的使用类型参数
- 如果一个类型的参数只出现在一个地方,请重新考虑你是否真的需要他
function f1<T>(arr:T[]){
return arr[0];
}
function f2<T extends any[] >(arr:T[])
{
return arr[0]
}
#### 从类型中创建泛型
- 泛型类型
- keyof类型操作符
- keyof类型操作符后面必须指的是一个类型
- typeof类型操作符
- typeof后面必须是一个变量
- 索引访问类型
- 条件类型
- 映射类型
- 模板字面量类型
泛型
- 声明泛型函数后,可以使用两种方式进行调用。一种是直接输入参数调用,让ts进行类型推断。一种是直接显式声明类型
- 泛型函数的应用
function identity<T>(params: T): T {
return params;
}
let myIndentity: <T>(arg: T) => T = identity;
let myIndentity2: <I>(arg: I) => I = identity;
let myIdenttity3: { <T>(arg: T): T } = identity;
interface myIndentity4 {
<T>(arg: T): T
}
let myIdenttity4:myIndentity4 = identity;
- 泛型接口的应用
interface Animal<T> {
name:T,
skip:(arg:T)=>T
}
- 泛型类的应用
class Dog<T>{
name: T
constructor(name: T) {
this.name = name;
}
getName(): T {
return this.name;
}
}
- 泛型约束
function getLength<T extends { length:number } >(params: T) {
return params.length;
}
function getLength<T>(params: Array<T>) {
return params.length;
}
- 在泛型约束中使用类型参数
// Key 类型属于 Type 对象类型中的某个 Key 值, 就是 Key 的取值范围是在 Type 对象的所有 key 值中获取的
function getProperty<Type, Key extends keyof Type>(obj: Type, key: Key) {
return obj[key]
}
- 在泛型中使用类类型
// 创建类的实例,工厂函数
function create<Type>(c: { new(): Type }): Type {
return new c();
}
keyof 类型操作符
- 用来接收一个对象
类型
,他会产生key的字符串或者是数字字面量的一个结合或者是一个联合类型
type Point = { x:number,y:number}
type P = keyOf Point // P 类型属于Point对象类型中的某个 key 值
const p1:P = 'x';
const p2:P = 'y';
typeof 类型操作符
- 只能去修饰某个变量或者是某个变量的属性,不要去标识函数的调用结果 tips:不是修饰的具体的变量的值
- ReturnType T:必须是
函数类型
ts中预定义的类型
tips:T
必须是函数类型(type/interface声明的类型)- 该关键字返回的是
T 函数
执行后的返回的类型
- 该关键字返回的是
let str = 'hello'; // string
let str2 = typeof str; // string
str2 = 'world';
type Fun = (arg: number) => boolean;
type K = ReturnType<Fun>;
function fn(): K { // boolean
return true;
}
function fn2() {
return {
x: 10,
y: 20
}
}
// 该方式不可取
let fn3: typeof fn2;
fn3 = function () {
return {
x: 222,
y: 666
}
}
let fn4: ReturnType<typeof fn2>;
fn4 = {
x: 111,
y: 222
}
索引类型
type Person = {
name:string,
age:number
}
type Age = Person['age']; // == number
let age:Age = 666;
type Person2 = [keyof Person];
let per1:Person2; // number / string
条件类型
interface IdLabel {
id: number
}
interface NameLable {
name: string
}
type NameOrId<T extends number | string> = T extends number ? IdLabel : NameLable;
function createLable<T extends number | string>(idOrName: T): NameOrId<T> {
throw ''
}
createLable('hello');
createLable(666);
条件类型约束
type Flatten<T> = T extends any[] ? T[number] : T;
// string
type Str = Flatten<string[]>;
// number
type Num = Flatten<number>
type MessageOf<T> = T extends { message: unknown } ? T['message'] : never;
type Address = {
message: string
}
// string
let str: MessageOf<Address>;
在条件类型内推理
type GetReturnType<Type> = Type extends (...args: never[]) => infer Return ? Return : never;
// number
type Num = GetReturnType<() => number>;
let num: Num = 111;
// string
type Str = GetReturnType<() => string>;
let str: Str = '111';
// boolean[]
type Bol = GetReturnType<(a: boolean, b: boolean) => boolean[]>;
let bol: Bol = [true];
// never
type Nev = GetReturnType<number>;
let nev: Nev = 11 as never;
function NumOrStr(arg: string | number): string | number {
return typeof arg === 'string' ? arg : arg + 1;
}
// number 、string
type NumOrS = ReturnType<typeof NumOrStr>;
let s:NumOrS = 'ss';
分布式条件数组
type toArray<T> = T extends any ? T[] : never;
type StrOrNumArr = toArray<string | number>;
let arr1:StrOrNumArr = [1,2,3];
let arr2:StrOrNumArr = ['s','s','d'];
类
- 知识点补充
- 类的所有方法都是定义在class的prototype上面的
- 类的内部有setter / getter 方法可以在设置或获取类的属性值的时候,对其进行拦截操作
- 类也有隐藏的的name属性 指的是class关键字后面紧跟的类名
- 除了私有属性,其他的属性和方法包括静态方法都会被子类继承
- 静态方法不需要实例化对象来调用,可以直接通过类名
.
的形式来调用 - 私有属性只能在类内部进行使用
- 静态方法不需要实例化对象来调用,可以直接通过类名
super
在这是指父类的构造函数,用来新建一个父类实例对象super
两种含义- 作为函数来使用,
super
指的是父类的构造函数,返回的是子类的实例- 作为函数使用的时候,必须是在构造函数中进行调用
- 作为对象来使用。
super
指向的是父类的原型,所以只能调用父类原型上的属性和方法,父类实例上的属性不可调用。- 调用的方法中的
this
指向的子类实例。 - 在静态方法中
super
指向的是父类,调用返回的是子类 - 使用
super.xxx
对属性进行赋值的时候,此时的super
指的是子类的this
- 调用的方法中的
- 作为函数来使用,
- 在继承父类后,子类必须得在构造函数中执行
super()
,原因是因为,es6的this
实例是在继承父类的属性和方法之后生成的。在对其进行添加自己的属性和方法 - 所以不可以在
super()
之前使用this
关键字- es5的继承机制:先创造一个独立子类实例对象,再将父类的方法添加到这个对象上,即实例在前,继承在后
- es6的继承机制:先将父类的属性和方法添加到一个空对象上,再将该对象作为子类的实例,即继承在前,实例在后
- 如果子类没有显式书写constructor 构造函数,在子类继承父类后,会隐式生成constructor构造函数,并且在构造函数内部会自动执行super()
- Object.getPrototypeOf() 获取类的父类
- mixin 混入的实现将多个对象合成一个对象
- 解构操作符
...
Object.assgin()
Reflect.ownKeys()
获取对象的全部key值组成一个数组并返回Object.getOwnPropertyDescriptor()
方法返回指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性)Object.getOwnPropertyNames()
方法返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组。hasOwnProperty()
实例检查自身是否有这个属性,不包括所属类的原型上的属性
- 解构操作符
- 类属性
- 属性!:type 可以排除该属性不为 null 或 undefined
- readonly
- readonly属性 只读属性
- 可以在构造函数中对只读属性进行赋值 及 在类定义初始化默认值的时候
- 其他情况下不可以对只读属性进行修改
- 构造器
- 构造函数不能有类型参数
- 构造函数不能有返回类型注释
- 方法
+ - Getters / Setters
- 如果只存在get,但没有set,则该属性自动是只读的
- 如果没有指定setter参数的类型,他将从getter的返回类型中推断出来
- 访问器和设置器必须具有相同的成员可见性
- 设置setter函数 传参数的时候,其参数的值的类型必须为getter函数返回值的类型
- Number.isFinite 标识这个数是不是可数的
- 索引签名
// s的类型定义 约束了Animal类里面的函数和属性的类型
class Animal {
[s: string]: boolean | ((s: string) => boolean)
x = true;
check(s:string) {
return this[s] as boolean;
}
}
- 类的继承
- implements
- 可以实现多个接口
- 类实现接口的时候,实现的接口的方法和属性不一定要和接口中定义的属性和方法一致,只要兼容就可以
- 实现带有可选属性的接口,并不能实现可选属性
interface Person {
age: number
run(): void
}
interface Job {
address: string
getAddress(): void
}
class Man implements Person, Job {
address: string;
age: number;
run(): void {
console.log("跑的相对快");
}
getAddress(): string {
return this.address;
}
}
- extends
- 类去继承其他的类
- 子类(派生类)继承父类(基类)重写父类的方法的时候,需要注意方法参数的兼容性问题
- 初始化顺序
- 基类的属性初始化,基类的构造函数执行
- 派生类的属性初始化,派生类的构造函数执行
继承内置类型
- extends Error
- 继承内置类型的时,在es5版本之后没问题,在es5版本之前继承内置类需要自己手动设置原型
class MsgError extends Error {
message: string;
constructor(s: string) {
super();
this.message = s;
Object.setPrototypeOf(this, MsgError.prototype);
}
throwMsg() {
return this.message;
}
}
类成员的可见性控制
- private / #
- 私有的。只能在当前类中进行访问
- public
- 公开的,任何对象在任何地方都可以访问
- protected
- 受保护的。能在当前类或子类中进行访问
- 静态成员
- 通过类名进行访问
- 可以在static前面加上可见性控制
- 在静态函数中,使用this ,this指向的是当前类。而不是指向当前类的实例
- static 区块
+ - 泛型类
- 静态成员不能使用类类型
- this 的类型缩小
class FileSystemObject {
// this 的类型缩小
isFile(): this is FileRep {
return this instanceof FileRep;
}
isDirectory(): this is Directory {
return this instanceof Directory;
}
isNetWorked(): this is NetWorked & this {
return this.networked;
}
constructor(public path: string, private networked: boolean) {
}
}
- 参数属性
class Animal {
skip: string
constructor(public s:string){
}
}
let cat = new Animal('hello');
// 可直接访问
console.log(cat.s);
- 类表达式
const Animal = class <T>{
age: T
getAge():T {
console.log(this.age);
return this.age;
}
}
- 抽象类
abstract class Animal {
abstract age: number
abstract getAge(): void
}
class Cat extends Animal {
age: number;
getAge(): void {
console.log(this.age);
}
}
let kf = new Cat();
kf.age = 3;
kf.getAge();
function fuc(Ctor: new () => Animal) {
const cat = new Ctor();
cat.age = 6;
cat.getAge()
}
// 所要填写的参数类不能为抽象类,并且为Animal类的子类
fuc(Cat);
-
类之间的关系
- 类B的包含类A的全部的属性和方法,类B的类型可以接受类A的实例
- 未给类声明任何属性和方法。拿类做参数类型,可以穿任意类型的值
-
模块 es moudle
- es2015中 import 和 export 的文件都被认为是一个模块,没有使用import 和export 的被认为是脚本文件,他是可以在全局范围内执行的
import XXX from '' / export default{}
import {} from '' / export
import XXX ,{} from '' export ,export default
- ts特定的模块方法
- 可以导出导入类型 type interface
import { Animal,type Cat,type Dog } from ""
- ES模块语法和CommonJS行为
import fs = require('fs');
const code = fs.readFileSync('./b.ts','utf-8');
- CommonJS 语法 require
- 导出 exports moudle.exports
- 导入 require