- 函数和类可以支持多种类型,增加的程序的可扩展性
- 不必写多条函数重载,联合类型声明,增强代码的可读性
- 灵活控制类型之间的约束
总结: 泛型不仅可以保持类型的一致性,又不失程序的灵活性,同时也可以通过泛型约束,控制类型之间的约束。从代码的上来看,可读性,简洁性,远优于函数重载,联合类型声明以及 any 类型的声明。
TypeScript 编译器在做类型检查的时,所秉承的一些原则,以及表现出的一些行为
作用: 辅助开发,提高开发效率
- 类型推断
- 类型兼容性
- 类型保护
不需要指定变量的类型(函数的返回值类型),Typescript 可以根据某些规则自动为其推断一个类型。
- 基础类型推断
- 最佳通用类型推断
- 上下文类型推断
- 前两者都是从右往左的推断,根据值去推断, 例如
let a = 1
// a 被推断的类型是number
- 最佳通用类型推断 例如
let b = [1, 'a']
// b 的最佳通用类型(string | number)[]
- 根据上下类型推断 例如 window.onkeydown = (event) => {} // 推断 event 为 KeyboardEvent
当类型推断不符合你的要求的时候,你可以使用类型断言 as,但是类型断言不能乱用,要对自己上下文充分了解
当一个类型Y可以被赋值给另一个类型X时候,我们就可以说类型X兼容类型Y
// 接口兼容性
interface X {
a: any,
b: any
}
interface Y {
a: any,
b: any,
c: any
}
let x: X = {a:1, b:2}
let y: Y = {a:1, b:2, c: 4}
x = y
y = x // 不兼容 x 缺少 c
// 成员少的兼容成员多的
函数的兼容性
- 参数个数
- 参数多的的兼容参数少的
- 可选参数和剩余参数
-
参数类型 - 对象参数类型
-
返回类型
枚举兼容性
- 枚举之间是不兼容的,但是枚举成员可以兼容数字和字符串
类的兼容性
- 静态类型和构造函数不参与兼容比较,比较的是实例,如果有私有成员,就不兼容了,除非存在继承关系
泛型的兼容性
// 交叉类型
interface DogInterface {
run():void
}
interface CatInterface {
jump():void
}
let pet: DogInterface & CatInterface = {
run(){},
jump(){}
}
// 联合类型
let a: number | string = 'a'
// 字面量联合类型 (只能是字面量中的一种)
let b: 'a' | 'b' | 'c'
// 对象的联合类型
interface Square {
kind: "square";
size: number;
}
interface Rectangle {
kind: "rectangle";
width: number;
height: number;
}
interface Circle {
kind: "circle";
radius: number;
}
type Shape = Square | Rectangle | Circle
function area(s: Shape) {
switch (s.kind) {
case "square":
return s.size * s.size;
case "rectangle":
return s.height * s.width;
case 'circle':
return Math.PI * s.radius ** 2
default:
return ((e: never) => {throw new Error(e)})(s)
}
}
console.log(area({kind: 'circle', radius: 1}))
let obj = {
a: 1,
b: 2,
c: 3
}
// function getValues(obj: any, keys: string[]) {
// return keys.map(key => obj[key])
// }
function getValues<T, K extends keyof T>(obj: T, keys: K[]): T[K][] {
return keys.map(key => obj[key])
}
console.log(getValues(obj, ['a', 'b']))
// console.log(getValues(obj, ['d', 'e']))
// keyof T
interface Obj {
a: number;
b: string;
}
let key: keyof Obj
// T[K]
let value: Obj['a']
// T extends U
将一个旧的类型生成一个新的类型
interface Obj {
a: string
b: string
c: string
}
// 映射类型 同态
type ReadonlyObj = Readonly<Obj>;
type PartialObj = Partial<Obj>;
type PickObj = Pick<Obj, 'a' | 'b'>
// 映射类型 非同态
type RecordObj = Record<'x'|'y', Obj>
// T extends U ? X : Y
type TypeName<T> =
T extends string ? "string" :
T extends number ? "number" :
T extends boolean ? "boolean" :
T extends undefined ? "undefined" :
T extends Function ? "function" :
"object";
type T1 = TypeName<string>
type T2 = TypeName<string[]>
// (A | B) extends U ? X : Y
// (A extends U ? X : Y) | (B extends U ? X : Y)
type T3 = TypeName<string | string[]>
type Diff<T, U> = T extends U ? never : T
type T4 = Diff<"a" | "b" | "c", "a" | "e">
// Diff<"a", "a" | "e"> | Diff<"b", "a" | "e"> | Diff<"c", "a" | "e">
// never | "b" | "c"
// "b" | "c"
type NotNull<T> = Diff<T, null | undefined>
type T5 = NotNull<string | number | undefined | null>
// Exclude<T, U>
// NonNullable<T>
// Extract<T, U>
type T6 = Extract<"a" | "b" | "c", "a" | "e">
// ReturnType<T>
type T8 = ReturnType<() => string>