TypeScript 高级类型
一、高级类型
- class
- 类型兼容性
- 交叉类型
- 泛型和keyof
- 索引签名类型和索引查询类型
- 映射类型
二、class
- 构造函数给变量赋值
- extends 继承
- implement 实现接口
- public 公开,所有可见,默认,可以省略
- protected:仅仅自己和子类可用
- private:私有的,只有自己可用
// 感叹号表示虽然没有初始化,但一定会有值
class Person {
name!: string
gender = '男'
}
let p = new Person()
p.name = '小乔'
p.gender = '女'
console.log(p)
class Person {
name: string
gender: string
age: number
constructor(name: string, gender: string, age: number) {
this.name = name
this.age = age
this.gender = gender
}
setName: (name: string) => void = (name) => {
this.name = name
}
setAge(age: number) {
this.age = age
}
}
let p = new Person('大乔', '女', 18)
interface IAction {
say(): void
}
class Animal {
age!: number
}
class Dog extends Animal implements IAction {
constructor(age: number) {
super()
this.age = age
}
say(): void {}
}
console.log(new Dog(17))
- readonly:只读修饰符,防止在构造之外的赋值行为,但是必须指定类型,否则为字面值常量
class Person {
readonly age: number = 18
constructor(age: number) {
this.age = age
}
}
三、类型兼容性
- 同类型的兼容
(method) Array<number>.forEach(callbackfn: (value: number, index: number, array: number[]) => void, thisArg?: any): void
// 有三个变量,所以以下方法兼容
let arr = [1, 2, 3, 4, 5, 6]
arr.forEach((item, a) => {
console.log(a + '、' + item)
})
- 成员多的可以赋值给成员少的
- 成员少的兼容成员多的
class Point {
x: number
y: number
}
class Point3D {
x: number
y: number
z: number
}
let p: Point = new Point3D()
- 接口、函数都有兼容性
interface Point {
x: number
y: number
}
interface Point2D {
x: number
y: number
}
interface Point3D {
x: number
y: number
z: number
}
// 接口必须赋值后,才能给另一个变量
let p1: Point = { x: 1, y: 2 }
let p2: Point2D = { x: 4, y: 5 }
let p3: Point3D = { x: 6, y: 7, z: 8 }
p1 = p2
p2 = p3
console.log(p1, p2, p3)
- 类和接口只要类型相同也可以兼容
interface Point {
x: number
y: number
}
class Point2D {
x: number
y: number
constructor(x: number, y: number) {
this.x = x
this.y = y
}
}
interface Point3D {
x: number
y: number
z: number
}
let p1: Point = { x: 1, y: 2 }
let p2: Point2D = new Point2D(4, 5)
let p3: Point3D = { x: 6, y: 7, z: 8 }
p1 = p2
p2 = p3
console.log(p1, p2, p3)
四、交叉类型
- 交叉类型的功能类似于接口继承
- 用于组合多个类型为一个类型(常用于对象类型)
class Person {
name = "";
age = 0;
}
class Point {
x = 0;
y = 0;
}
type Temp = Person & Point;
let p: Temp = { name: "", age: 0, x: 0, y: 0 };
p.name = "张三";
console.log(p);
五、泛型
- 在保证类型安全的前提下,实现复用
- 利用类型推断机制,可以简化泛型调用
function Say<T>(t: T) {
console.log(typeof t, t);
}
Say<number>(19);
Say<string>("张三");
// 可以简化泛型类型调用
Say(29);
Say("李四");
- 泛型约束
- 指定具体类型
- 添加约束 extends
// 指定具体类型,就会有length的属性
function Say<T>(t: T[]) {
console.log(typeof t, t, t.length);
}
Say([29, 90, 25]);
Say(["李四", "王五"]);
// 添加约束,要求传入的参数必须具有length属性
interface ILength {
length: number;
}
function Say<T extends ILength>(t: T) {
console.log(typeof t, t, t.length);
}
Say([29, 90, 25]);
Say(["李四", "王五"]);
- 泛型接口
- ctrl+鼠标左键或者F12键,查看定义
interface IdFun<T> {
id: (v: T) => T
ids: () => T[]
}
let a: IdFun<number> = {
id(v) {
return v
},
ids() {
return [1, 2, 3, 4]
},
}
console.log(a.id(6))
console.log('ids :>> ', a.ids())
- 泛型类
class GenericNumber<T> {
defaultNum: T
add: (a: T, b: T) => T
constructor(v: T) {
this.defaultNum = v
}
}
// 因为有构造,所以能自动推断出类型,如果没有就需要显式指定类型
const myGenericNum = new GenericNumber(10)
myGenericNum.defaultNum = 0
myGenericNum.add = (a, b) => {
return a + b
}
- 泛型工具类
- Partial<T>
- Readonly<T>
- Pick<T, keys>
- Record<Keys, T>:构造一个对象类型,属性为k,类型为T
interface Props {
name: string
age: number
}
// 原有类型没有发生变化,生成一个新类型,新类型每个属性都是可选类型
type propsNew = Partial<Props>
let a: propsNew = {}
// 将所有属性变成只读
type propReadonly = Readonly<Props>
let b: propReadonly = { name: '张三', age: 10 }
// 从中选择一些属性,两个参数
type propPick = Pick<Props, 'name' | 'age'>
let c: propPick = { name: '', age: 10 }
c.name = '李四'
c.age = 18
// 构造一个新类型,属性键为keys,属性每个类型为T
type RecordObj = Record<'a' | 'b' | 'c', string[]>
let d: RecordObj = {
a: [''],
b: [''],
c: [''],
}
type RecordObj2 = Record<'a' | 'b' | 'c', number>
let e: RecordObj2 = {
a: 1,
b: 2,
c: 3,
}
六、索引签名类型和索引查询类型
- 当无法确定对象中有哪些属性时,用索引签名类型
- key只是个占位符,可以换成任意类型
interface ObjAny {
[key: string]: number;
}
let a: ObjAny = {
a: 1,
b: 2,
hello: 6,
};
// Array<T> 就有这种用法,仿造的
interface MyArray<T> {
[k: number]: T;
}
let c = [1, 2, 4, 7];
- 映射类型
- 基于旧类型创建的新类型,减少重复,提高开发效率
- 该类型是基于索引签名类型的
- key in P:key可以是P属性中的任意一个
- 只能在类型别名中使用,不能在接口中使用
// 复合类型
type P = "a" | "b" | "c";
type M = { [key in P]: number };
let temp: M = {
a: 1,
b: 2,
c: 4,
};
let d = [1, 3, 4, 5, 8, 2];
// 对象中获取
type Person = {
name: string;
age: number;
birth: Date;
};
type H = { [key in keyof Person]: number };
- 系统内置的映射类型
- keyof T 表示获取泛型的所有键
- []后面的问号,表示是可选的
- 冒号后面的T[P]表示获取T中每个键对应的类型
type Required<T> = {
[P in keyof T]-?: T[P];
};
/**
* Make all properties in T readonly
*/
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
/**
* From T, pick a set of properties whose keys are in the union K
*/
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
/**
* Construct a type with a set of properties K of type T
*/
type Record<K extends keyof any, T> = {
[P in K]: T;
};
- T[P]:属于索引查询类型或索引访问类型
// 获取person中age的类型
type f = Person["age"];
世界上没有什么事情是跑步解决不了的,如果有,那就再跑一会!